Rust 变量的所有权如何在迭代之间工作?
我正在努力学习rust,并考虑将实施链表作为一个实践问题来理解所有权/借用概念,我现在很难理解Rust 变量的所有权如何在迭代之间工作?,rust,Rust,我正在努力学习rust,并考虑将实施链表作为一个实践问题来理解所有权/借用概念,我现在很难理解 LinkedList的push方法应如下所示: t = 0 | root: None | push 5 t = 1 | root: { value: 5, next: None } | push 6 t = 2 | root: { value: 5, next: { value: 6, None } } | 下面是尝试执行相同操作的代码: #[derive(Debug, Clone)] struct
LinkedList
的push
方法应如下所示:
t = 0 | root: None | push 5
t = 1 | root: { value: 5, next: None } | push 6
t = 2 | root: { value: 5, next: { value: 6, None } } |
下面是尝试执行相同操作的代码:
#[derive(Debug, Clone)]
struct Node {
value: u32,
next: Option<Box<Node>>,
}
impl Node {
fn new(value: u32) -> Node {
Node { value, next: None }
}
}
#[derive(Debug, Clone)]
struct LinkedList {
root: Option<Box<Node>>,
}
impl LinkedList {
fn new(node: Option<Box<Node>>) -> LinkedList {
LinkedList { root: node }
}
fn push(self, node: Option<Box<Node>>) {
let maybe_node = self.root;
loop {
match maybe_node {
Some(tail_node) => { // use of moved value. std::boxed::Box<Node> doesn't implement copy trait. --- (1)
if tail_node.next.is_none() {
tail_node.next = node; // tail_node is not mutable. --- (2)
break;
};
}
_ => (),
}
}
}
}
fn main() {
let mut node = Node::new(0);
let linked_list = LinkedList::new(Some(Box::new(node)));
for number in 1..5 {
node = Node::new(number);
linked_list.push(Some(Box::new(node))); // move occurs. Value moved here in a previous iteration --- (3)
}
println!("{:?}", linked_list);
}
#[派生(调试、克隆)]
结构节点{
值:u32,
下一步:选择,
}
impl节点{
fn新(值:u32)->节点{
节点{值,下一个:无}
}
}
#[派生(调试、克隆)]
结构链接列表{
根:选项,
}
impl链接列表{
fn新建(节点:选项)->LinkedList{
LinkedList{root:node}
}
fn推送(自身,节点:选项){
让node=self.root;
环路{
匹配节点{
Some(tail_node)=>{//使用移动值。std::boxed::Box未实现复制特性。--(1)
如果tail\u node.next.is\u none(){
tail\u node.next=node;//tail\u节点不可变。--(2)
打破
};
}
_ => (),
}
}
}
}
fn main(){
让mut node=node::new(0);
让linked_list=LinkedList::new(Some(Box::new(node));
对于1..5中的数字{
节点=节点::新(编号);
linked_list.push(Some(Box::new(node));//发生移动。值在上一次迭代中移动到此处---(3)
}
println!(“{:?}”,链表);
}
我不理解“移动发生”错误(1,3)。我不清楚值移动到了哪里?迭代似乎正在导致所有权发生变化,但我看不出是如何变化的
此外,错误(2)是我实现的最佳方式?在Rust中,有两种方式是处理所有权,即移动语义或借用语义。这里有一些关于理解它的规则 第一条规则是,每条数据在同一时间只能有一个所有者。如果将某个变量分配给另一个变量,则可以有效地移动数据,数据将归新所有者所有 第二条规则是,如果你有一些属于某人的数据,但你想读它,那么你可以借用它。借用本质上是获取对数据的引用,这些数据由其他人拥有 现在回到你的问题上来。在函数声明中,您已将第一个参数声明为
self
fn推送(自身,节点:选项){
让node=self.root;
环路{
匹配节点{
Some(tail_node)=>{//使用移动值。std::boxed::Box未实现复制特性。--(1)
如果tail\u node.next.is\u none(){
tail\u node.next=node;//tail\u节点不可变。--(2)
打破
};
}
_ => (),
}
}
}
这本质上意味着,当你调用你的函数时,你拥有了self的所有权,因此你使任何以前的所有者无效。循环中发生的情况是,在第一次迭代中,该值被移动到函数中,不再属于链接列表
。在第二次迭代中,您再次尝试访问数据,但它不再有效,因为它已被移动到函数中
为了避免您的问题,您需要声明您的函数,如下所示:
fn推送(&mut self,节点:选项){
让node=self.root;
环路{
匹配节点{
Some(tail_node)=>{//使用移动值。std::boxed::Box未实现复制特性。--(1)
如果tail\u node.next.is\u none(){
tail\u node.next=node;//tail\u节点不可变。--(2)
打破
};
}
_ => (),
}
}
}
在上面的声明中,您表示您正在借用self
,并且希望对其进行更改(这就是为什么我们有&mut
,而不仅仅是&
)
有关更多详细信息,请参阅。您的
推送方法消耗链接列表
,因为它按值获取自我
,而不是&mut self
“我正试图学习生锈并考虑将实现链接列表作为一个实践问题”您成为经典错误之一的受害者。最著名的是从不创建自引用数据结构,但这一点鲜为人知:。感谢您提供详细的答案。“循环中发生的事情是,在第一次迭代中,值被移动到函数中,不再属于链接列表”好的,我很难理解这一点,但这意味着如果我调用。按一下,实例链接列表“移动”到函数中?所以,如果我只是阅读的话,&self
就足够了?而不是变异什么?我理解这种混乱。从我的角度看,你似乎已经理解了一切。如果只有&
,则只能读取,这也适用于结构的所有内部字段,因此,如果将&
转换为结构,则无法更改结构或结构中的任何数据。由于您有tail\u node.next=node
分配,因此您需要更改选项的内容&mut