Rust 无法移出对`&;的取消引用;调用Option::unwrap时的mut`-指针
以下代码未编译:Rust 无法移出对`&;的取消引用;调用Option::unwrap时的mut`-指针,rust,Rust,以下代码未编译: struct Node { left: Option<Box<Node>>, right: Option<Box<Node>>, } impl Node { fn new() -> Node { Node { left: None, right: None, } } } fn init_tree(root: &mut Box<Node>, n: int)
struct Node {
left: Option<Box<Node>>,
right: Option<Box<Node>>,
}
impl Node {
fn new() -> Node {
Node { left: None, right: None, }
}
}
fn init_tree(root: &mut Box<Node>, n: int) {
match n {
0 => {},
_ => {
root.left = Some(box Node::new());
root.right = Some(box Node::new());
init_tree(&mut root.left.unwrap(), n - 1);
init_tree(&mut root.left.unwrap(), n - 1);
}
}
}
fn main() {
let mut root: Box<Node> = box Node::new();
init_tree(&mut root, 10);
}
我怎样才能纠正这个错误呢?铁锈编译器并不自诩智力卓越或学术崇高;它完全按照你告诉它的去做,而不是你的意思或想要的 在本例中,当您说
&mut root.left.unwrap()
时,您想要的是通过可变引用获取选项
,并为您提供一个&mut框
;但这绝对不是你让它做的
您让它做的是对root.left.unwrap()
的结果进行可变引用;让我们看看签名:
所以root.left.unwrap()
所做的是它消耗root.left
,产生一个框
对象(如果它是无
,则会惊慌失措)。然后剩下整个表达式&mut root.left.unwrap()
生成&mut Box
,并使用root.left
,从而部分使用root
。现在,您肯定不允许这样做,因为它会留下需要销毁的root
,但是您只有一个可变的引用,它不是您要销毁的。因此出现了错误
解决方法不是使用展开
,而是自己编写一个合适的匹配
表达式。记住,.unwrap()
只是匹配self{Some(x)=>x,None=>panic!(…)}
,这并没有什么神奇之处
你会得到这样的结果:
fn init_tree(root: &mut Node, n: int) {
if n != 0 {
root.left = Some(box Node::new());
root.right = Some(box Node::new());
init_tree(match root.left { Some(box ref mut x) => x, None => unreachable!() }, n - 1);
init_tree(match root.right { Some(box ref mut x) => x, None => unreachable!() }, n - 1);
}
}
(恐怕,box ref mut x
部分有点纠结;它从box
生成一个&mut
,box
表示“取消对值的装箱”,而ref mut
表示“然后对其进行可变引用”。请记住,在模式中,所有内容都是从后到前的,框
和&
意味着与它们在外部所做的相反,整个批次从左到右读取,而不是从右到左读取。此外,虽然您可以使用&mut框
,但我建议使用&mut节点
,这样可以删除一个级别的间接。顺便说一句,如果您仍在使用&mut Box
,root.left.as_mut().unwrap()
也可以。)
这可以通过不立即将内容填充到根目录中来改进:
fn init_tree(root: &mut Node, n: int) {
if n != 0 {
let mut left = box Node::new();
let mut right = box Node::new();
init_tree(&mut *left, n - 1);
init_tree(&mut *right, n - 1);
root.left = Some(left);
root.right = Some(right);
}
}
这一点要简单得多,&mut*left
从右到左被解读为“解除引用left
(这将从框中获取节点
),然后获取对它的可变引用(这将获取&mut节点
).Rust编译器并不自诩为知识卓越或学术崇高;它完全按照你告诉它的去做,而不是按照你的意思或想要的去做
在本例中,当您说&mut root.left.unwrap()
时,您想要的是通过可变引用获取选项
,并为您提供一个&mut框
;但这绝对不是您实际告诉它的
您让它做的是对root.left.unwrap()
的结果进行可变引用;让我们看看签名:
所以root.left.unwrap()
所做的是它消耗root.left
,产生一个框
对象(或者如果它是无
),那么就剩下整个表达式和mut root.left.unwrap()
生成&mut-Box
,并使用根目录。左,因此部分根目录
。现在绝对不允许这样做,因为这样会使根目录
需要销毁,但您只有一个对它的可变引用,它不是您要销毁的。因此出现了错误
解决方法不是使用unwrap
,而是自己编写一个合适的match
表达式。记住,.unwrap()
只是match self{Some(x)=>x,None=>panic!(…)}
,这并没有什么神奇之处
你会得到这样的结果:
fn init_tree(root: &mut Node, n: int) {
if n != 0 {
root.left = Some(box Node::new());
root.right = Some(box Node::new());
init_tree(match root.left { Some(box ref mut x) => x, None => unreachable!() }, n - 1);
init_tree(match root.right { Some(box ref mut x) => x, None => unreachable!() }, n - 1);
}
}
(恐怕,box ref mut x
部分有点纠结;它从box
生成一个&mut
,box
表示“取消对值的装箱”,而ref mut
表示“然后对其进行可变引用”。请记住,在模式中,所有内容都是从后到前的,框
和&
意味着与它们在外部所做的相反,整个批次从左到右读取,而不是从右到左读取。此外,虽然您可以使用&mut框
,但我建议使用&mut节点
,这样可以删除一个级别的间接。顺便说一句,如果您仍在使用&mut Box
,root.left.as_mut().unwrap()
也可以。)
这可以通过不立即将内容填充到根目录中来改进:
fn init_tree(root: &mut Node, n: int) {
if n != 0 {
let mut left = box Node::new();
let mut right = box Node::new();
init_tree(&mut *left, n - 1);
init_tree(&mut *right, n - 1);
root.left = Some(left);
root.right = Some(right);
}
}
这一点要简单得多,&mut*left
从右到左被解读为“解除引用left
(这将从框中获取节点
),然后获取对它的可变引用(这将获取&mut节点
).上面的代码应该是这样的:let mut left=…;let mut right=…;无论如何,你的答案很好。谢谢!是的,我确实忘记了mut
,如果你想改变值,就需要它。修改,谢谢!上面的代码应该是这样的:let mut left=…;let mut right=…;不管怎样,你的答案是太好了。谢谢!是的,我确实忘记了那里的mut
,如果您希望对值进行变异,那么这是必需的。修改,谢谢!仅供参考,您的代码将左
初始化两次;我希望这不会让您感到惊讶!^ ^仅供参考,您的代码将左
初始化两次;我希望您不会感到惊讶^_^