Struct 调用采用“self”的方法时,不会修改数据结构`
我正在写一个二叉树结构,我在Struct 调用采用“self”的方法时,不会修改数据结构`,struct,rust,Struct,Rust,我正在写一个二叉树结构,我在insert函数中遇到了问题。调用函数在我的节点中插入数据后,该节点不会被修改 use std::ptr; #[derive(Clone, Copy)] struct Node<T> { data: Option<T>, left: *mut Node<T>, right: *mut Node<T>, } impl<T> Node<T> { pub fn new
insert
函数中遇到了问题。调用函数在我的节点中插入数据后,该节点不会被修改
use std::ptr;
#[derive(Clone, Copy)]
struct Node<T> {
data: Option<T>,
left: *mut Node<T>,
right: *mut Node<T>,
}
impl<T> Node<T> {
pub fn new(data: T) -> Node<T> {
Node {
data: Some(data),
left: ptr::null_mut(),
right: ptr::null_mut(),
}
}
pub fn insert(mut self, data: T) {
let tmp = self.data.unwrap();
self.data = None;
self.left = &mut Node::new(data);
self.right = &mut Node::new(tmp);
}
}
impl<T: std::fmt::Display> std::fmt::Display for Node<T>
where T: std::fmt::Debug
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self.data {
Some(ref x) => {
write!(f, "Node data: {}, left: {}, right: {}", x,
if self.left.is_null() {"null"} else {"not null"},
if self.right.is_null() {"null"} else {"not null"},
)
}
None => {
write!(f, "Node data: None, left: {}, right: {}",
if self.left.is_null() {"null"} else {"not null"},
if self.right.is_null() {"null"} else {"not null"},
)
}
}
}
}
fn main() {
let mut root: Node<i32> = Node::new(32);
println!("Root before insert : {}", root);
root.insert(42);
println!("Root after insert: {}", root);
}
我的节点在函数插入后未被修改。我能做些什么来解决这个问题?既然您看起来很困惑,让我们开始吧 首先,没有理由使用原始指针。此外,我建议不要使用
Copy
,因为它只会隐藏所有权问题。最后,派生调试要比手动实现格式化容易得多(并且它允许以更自动化的方式试验结构的布局)
没有什么悬而未决的问题,让我们转到insert
:
impl<T> Node<T> {
fn insert(&mut self, data: T) {
let current = self.data.take().expect("Cannot insert in empty node!");
self.left = Some(Box::new(Node::new(current)));
self.right = Some(Box::new(Node::new(data)));
}
}
还有 既然你看起来很困惑,让我们开始吧
首先,没有理由使用原始指针。此外,我建议不要使用Copy
,因为它只会隐藏所有权问题。最后,派生调试要比手动实现格式化容易得多(并且它允许以更自动化的方式试验结构的布局)
没有什么悬而未决的问题,让我们转到insert
:
impl<T> Node<T> {
fn insert(&mut self, data: T) {
let current = self.data.take().expect("Cannot insert in empty node!");
self.left = Some(Box::new(Node::new(current)));
self.right = Some(Box::new(Node::new(data)));
}
}
还有 您是指&mut self
,因为您是按值获取节点的。。。(如果您的节点
不是副本
,您会注意到这一点)。@MatthieuM。当我试图将self.data.unwrap()
中的值复制到tmp
中时,使用&mut self
会导致有关借用内容的错误,这是一个单独的问题;使用&mut self
是修改方法受体的唯一方法。另一种解决方案是使用mut self
并返回Node
,然后将调用站点更改为root=root.insert(…)代码>。我们可以帮助解决任何一种情况,所以只需选择您喜欢的任何一种。我知道返回Node
是解决问题的一种方法,但我想知道是否有一种方法可以更好地执行OOP-like@MatthieuM. 这将是一个难以回答的问题。请注意,OP通过self.left=&mut Node::new(data)
为内存安全埋下了一颗巨大的地雷。一旦这些值被取消引用。。。。Boooom.你是说&mut self
,因为你是按值获取节点的。。。(如果您的节点
不是副本
,您会注意到这一点)。@MatthieuM。当我试图将self.data.unwrap()
中的值复制到tmp
中时,使用&mut self
会导致有关借用内容的错误,这是一个单独的问题;使用&mut self
是修改方法受体的唯一方法。另一种解决方案是使用mut self
并返回Node
,然后将调用站点更改为root=root.insert(…)代码>。我们可以帮助解决任何一种情况,所以只需选择您喜欢的任何一种。我知道返回Node
是解决问题的一种方法,但我想知道是否有一种方法可以更好地执行OOP-like@MatthieuM. 这将是一个难以回答的问题。请注意,OP通过self.left=&mut Node::new(data)
为内存安全埋下了一颗巨大的地雷。一旦这些值被取消引用。。。。Boooom.是的,我确信数据
需要作为插入选项。否则,您知道为什么它与Box
一起工作而不与原始指针一起工作吗?谢谢你的回答,我修改了你的代码,做了我想做的事情,很有魅力,谢谢@Bl4ckb0ne:将None
分配给self.data
在take
之后是不必要的<代码>获取
已获取选项的内容
并将其替换为无
。至于原始指针:您无意中创建了一个指向堆栈上某个变量的指针,当您尝试取消引用它时,该指针会崩溃。原始指针功能强大且不安全(取消引用它们需要unsafe
关键字)<代码>框
会将内容放在堆上,并为您管理生存期。是的,我确信数据
需要作为插入选项。否则,您知道为什么它与Box
一起工作而不与原始指针一起工作吗?谢谢你的回答,我修改了你的代码,做了我想做的事情,很有魅力,谢谢@Bl4ckb0ne:将None
分配给self.data
在take
之后是不必要的<代码>获取
已获取选项的内容
并将其替换为无
。至于原始指针:您无意中创建了一个指向堆栈上某个变量的指针,当您尝试取消引用它时,该指针会崩溃。原始指针功能强大且不安全(取消引用它们需要unsafe
关键字)<代码>框
将把内容放在堆上,并为您管理生存期。
impl<T> Node<T> {
fn insert(&mut self, data: T) {
let current = self.data.take().expect("Cannot insert in empty node!");
self.left = Some(Box::new(Node::new(current)));
self.right = Some(Box::new(Node::new(data)));
}
}
fn main() {
let mut root: Node<i32> = Node::new(32);
println!("Root before insert : {:?}", root);
root.insert(42);
println!("Root after insert: {:?}", root);
}