Rust 在“中匹配可变选项引用”之间有什么区别;如果让一些(参考mut x)=选项;及;如果让某些(x)=选项.as_mut()“;? 背景

Rust 在“中匹配可变选项引用”之间有什么区别;如果让一些(参考mut x)=选项;及;如果让某些(x)=选项.as_mut()“;? 背景,rust,reference,mutable,Rust,Reference,Mutable,考虑一个玩具问题,其中我有一个表示链表节点的节点结构,我想创建一个函数来构建一个值为1到9的列表。以下代码按预期工作: struct Node { val: i32, next: Option<Box<Node>>, } fn build_list() -> Option<Box<Node>> { let mut head = None; let mut tail = &mut head; f

考虑一个玩具问题,其中我有一个表示链表节点的
节点
结构,我想创建一个函数来构建一个值为1到9的列表。以下代码按预期工作:

struct Node {
    val: i32,
    next: Option<Box<Node>>,
}

fn build_list() -> Option<Box<Node>> {
    let mut head = None;
    let mut tail = &mut head;
    for n in 1..10 {
        *tail = Some(Box::new(Node {val: n, next: None}));
        if let Some(ref mut x) = tail {
            tail = &mut x.next;
        };
    }
    head
}
编译错误:

错误[E0506]:无法分配给“*tail”,因为它是借用的
-->src/main.rs:72:9
|
72 |*tail=Some(Box::new(节点{val:n,next:None}));
|         ^^^^^
|         |
|借来的“*tail”的赋值发生在此处
|借来以后用在这里
73 |         {
74 |如果让一些(x)=尾{
|----此处借用“*tail”
错误[E0499]:一次不能将“*tail”作为可变项借用多次
-->src/main.rs:74:30
|
74 |如果让一些(x)=尾{
|^^^^可变借用在循环的上一次迭代中从这里开始
问题: 在这个例子中,两者的区别是什么

if let Some(ref mut x) = tail

?

(作为一个学习锈菌的初学者)我本以为这些匹配表达式是等价的,但显然我忽略了一些细微的差别

更新 我从我的原始示例中清理了代码,因此我不需要为列表的开头添加占位符元素。区别(和编译错误)仍然存在,我只是在分配给借用的
*tail
时得到了一个额外的编译错误

更新2 (这只是一个奇怪的观察,无助于回答最初的问题) 在考虑了@Emoun的答案之后,编译器应该能够知道
tail
在循环的每次迭代中都在变化(这样它就可以确保每次借用的
&mut x.next
是不同的),这听起来很重要(在第一个工作示例中)。因此,我做了一个实验,通过在
tail=&mut x.next;
赋值中添加一个
if n%2==0
条件来更改代码,使编译器无法判断情况是否如此。果然,这导致了一个与另一个类似的编译错误:

fn build_list() -> Option<Box<Node>> {
    let mut head = None;
    let mut tail = &mut head;
    for n in 1..10 {
        *tail = Some(Box::new(Node {val: n, next: None}));
        if let Some(ref mut x) = tail {
            if n % 2 == 0 {
                tail = &mut x.next;
            }
        };
    }
    head
}

代码的第二个版本失败的原因是rust的方法/函数总是借用整个对象,而不是它们的一部分

在您的案例中,这意味着
tail.as_mut()
可变地借用
tail
,并且只要使用
tail
,此借用将保持有效:

。。。
对于1..10中的n{
*tail=Some(Box::new(Node{val:n,next:None}));//第二次迭代中出错,
//“尾巴”已经被借用了

if let Some(x)=tail.asmut(){/
if let Some(x)=tail
似乎也能工作。不幸的是,我没有对任何情况的解释。似乎
tail.asmut()的返回值的生存期
tail
相同,因此只是一个编译器限制。在循环中移动
让tail=&mut head
使其工作。看起来非常相似。任何想知道为什么
Some(x)
可以匹配
&mut选项类型的人都应该查找。@CoronA,
如果让Some(x)=tail
确实有效,这也让我感到惊讶(学到了一些新东西,谢谢!)。这仍然不能解释为什么它与
tail=&mut head
(而不是
&mut x.next
)一起作为
case。如果你这样做,我认为程序的逻辑是不一样的。但是,它确实可以编译,因为如果你把所有尾部都分配给
head
,你就永远不会有
tail
借用它自己,它们都会借用
head
。我相信逻辑不是这个例子的重点,我也不认为借用它自己是一个正确的参数,由于
tail
是一个指针,
tail
的指针对象将在调用
tail后被重新借用。as_mut()
,那么
tail
将以可变方式借用
x。接下来
将以可变方式借用。所有这些是
x
可以多次借用(而不是
tail
)。如果您使用
tail=&mut head
我们的
x
将成为
head
,并且
head
将作为可变项被多次借用,那么为什么它允许多次借用head呢?@luca_moller
x
在每个迭代中都是不同的变量,因为您使用
If let-let-If-let(参考mut x)创建了一个新的变量=tail
。因此,没有连接到从一个迭代到下一个迭代的
x
的借用。是的,借用
x
允许编译器看到没有从一个迭代到下一个迭代的借用。感谢您让我知道借用检查器有更多的功能:)…只需将
作为mut
忽略即可,
&mut*tail
也违反了与
as_mut()
相同的借用检查器规则。
if let Some(x) = tail.as_mut()
fn build_list() -> Option<Box<Node>> {
    let mut head = None;
    let mut tail = &mut head;
    for n in 1..10 {
        *tail = Some(Box::new(Node {val: n, next: None}));
        if let Some(ref mut x) = tail {
            if n % 2 == 0 {
                tail = &mut x.next;
            }
        };
    }
    head
}