如何通过借用 Rust 来正确管理所有权?
How to manage properly ownership with borrowing in Rust?
我是 Rust 世界的新手,仍然不完全理解 ownership/borrowing/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
到 return 对新 Node
的引用放在 next
里面,引用需要是 return 的一部分类型。您不能将节点移动(转移所有权)到 next
中,同时还 returning 它;这不是所有权的运作方式:
fn populate(next: &mut Option<Box<Node>>) -> Option<&mut Node> {
// here: ^^^^
您可能会尝试 return 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>
,即 &Box<Node>
。取消引用(即 *
)next_as_ref_unwrap
尝试移动,这不能从借用的变量中完成。
问题是您有 next
,其中(基本上)包含一个 Node
,但是,您想要 return Node
。这就提出了一个问题:你想 return 另一个(即 new Node
),还是你想提取(即 take
) Node
来自 next
和 return 它。如果你想 take
和 return 它:
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
,这个 next
本质上用作局部变量并在之后生成 None
(因为我们 take
。
您可能想决定 populate
实际上应该做什么。
- 是否应该修改
None
?为什么 return 值 Option<None>
?它应该是 return next
的旧值吗? (为什么 return 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)
}
我是 Rust 世界的新手,仍然不完全理解 ownership/borrowing/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
到 return 对新 Node
的引用放在 next
里面,引用需要是 return 的一部分类型。您不能将节点移动(转移所有权)到 next
中,同时还 returning 它;这不是所有权的运作方式:
fn populate(next: &mut Option<Box<Node>>) -> Option<&mut Node> {
// here: ^^^^
您可能会尝试 return 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>
,即 &Box<Node>
。取消引用(即 *
)next_as_ref_unwrap
尝试移动,这不能从借用的变量中完成。
问题是您有 next
,其中(基本上)包含一个 Node
,但是,您想要 return Node
。这就提出了一个问题:你想 return 另一个(即 new Node
),还是你想提取(即 take
) Node
来自 next
和 return 它。如果你想 take
和 return 它:
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
,这个 next
本质上用作局部变量并在之后生成 None
(因为我们 take
。
您可能想决定 populate
实际上应该做什么。
- 是否应该修改
None
?为什么 return 值Option<None>
?它应该是 returnnext
的旧值吗? (为什么 returnOption<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)
}