我在Rust世界里是个新手,还没有完全理解所有权借贷lifetime的工作原理。 我有这个例子来证明一个挣扎。
struct Node {
value: bool,
next: Option<Box<Node>>
}
fn populate(next: &mut Option<Box<Node>>) -> Option<Node> {
let node = Node { value: true, next: None };
let result = Some(Box::new(node));
*next = result;
Some(*next.unwrap())
}
fn main() {
let mut node = Node {
value: false,
next: None
};
let result = populate(&mut node.next);
println!("{}", node.unwrap().value);
println!("{}", result.unwrap().value);
}
我不明白为什么移动这种方式可以用。
fn populate(next: &mut Option<Box<Node>>) -> Option<Node> {
let node = Node { value: true, next: None };
let result = Some(Box::new(node));
// *next = result;
Some(*result.unwrap() /* *next.unwrap() */)
}
但另一种方式却不行
fn populate(next: &mut Option<Box<Node>>) -> Option<Node> {
let node = Node { value: true, next: None };
let result = Some(Box::new(node));
*next = result;
Some(*(*next.as_ref().unwrap())) // or Some(*next.unwrap())
}
如何正确地转移所有权(就像上面的例子一样),不需要复制,而是借用突变的下一个引用(并且不添加额外的参数)?我还是不清楚这部分......
如果你想 populate
返回对新的 Node
内置于 next
,引用需要成为返回类型的一部分。你不能将节点的所有权转移到 next
的同时也要返回它,这不是所有权的工作方式。
fn populate(next: &mut Option<Box<Node>>) -> Option<&mut Node> {
// here: ^^^^
你可以尝试返回 Some(&mut *next.unwrap())
但这是行不通的,因为 unwrap
需要 self
的值。幸运的是,有一个方便的功能,在 Option
会带你直接从 &mut Option<Box<Node>>
到 Option<&mut Node>
, as_deref_mut
:
fn populate(next: &mut Option<Box<Node>>) -> Option<&mut Node> {
let node = Node {
value: true,
next: None,
};
*next = Some(Box::new(node));
next.as_deref_mut()
}
fn populate(next: &mut Option<Box<Node>>) -> Option<Node> {
let node = Node { value: true, next: None };
let result = Some(Box::new(node));
*next = result;
Some(*result.unwrap() /* *next.unwrap() */)
}
按照编译器的建议按摩代码,可能会导致你写的东西。现在,拿着它,引入中间变量并注释类型(看看是怎么回事),就会得到这样的结果。
fn populate2(next: &mut Option<Box<Node>>) -> Option<Node> {
let node : Node = Node { value: true, next: None };
let result : Option<Box<Node>> = Some(Box::new(node));
*next = result;
let next_as_ref : Option<&Box<Node>> = next.as_ref();
let next_as_ref_unwrap : &Box<Node> = next_as_ref.unwrap();
let next_as_ref_unwrap_deref : Box<Node> = *next_as_ref_unwrap; // <- error here!
Some(*next_as_ref_unwrap_deref) // or Some(*next.unwrap())
}
let next_as_ref_unwrap_deref : Box<Node> = *next_as_ref_unwrap;
失败,因为 next_as_ref_unwrap
是借来的 Box<Node>
即a &Box<Node>
. Dereferencing(即 *
) next_as_ref_unwrap
试图移动,这不能从借来的变量中完成。
问题是,你有 next
,其中包含(基本上)一个 Node
然而,你想 返回 a Node
. 这就提出了一个问题。你是否要返回另一个(即 新的 Node
),还是要提取(即) take
)的 Node
从 next
并将其退回。如果你想 take
并将其返回。
fn populate(next: &mut Option<Box<Node>>) -> Option<Node> {
let node = Node { value: true, next: None };
let result = Some(Box::new(node));
*next = result;
next.take().map(|boxed_node| *boxed_node)
}
上面的代码可以编译,但至少是可疑的,因为它接受了一个... next
本质上是作为一个局部变量使用的,并使之成为 None
之后(因为我们 take
从它)。)
你可能要决定什么是 populate
其实应该做的。
None
? 为什么返回值 Option<None>
? 是否应该返回 next
的旧值?(为什么要返回 Option<Node>
而不是 Option<Box<Node>>
然后呢?)码。
fn populate_returning_old_val(next: &mut Option<Box<Node>>) -> Option<Node> {
std::mem::replace(
next,
Some(Box::new(Node { value: true, next: None }))
).take().map(|boxed_node| *boxed_node)
}