为什么添加 & 会导致生锈?[复制]

Why would adding a & cause a move in rust? [duplicate]

提问人:violet 提问时间:9/26/2023 最后编辑:violet 更新时间:9/26/2023 访问量:60

问:

以下编译:

#[derive(Debug)]
enum List {
    Cons(Rc<RefCell<i32>>, Rc<List>),
    Nil,
}

use std::ops::Deref;
use crate::List::{Cons, Nil};
use std::cell::RefCell;
use std::rc::Rc;

fn main() {
    let value = Rc::new(RefCell::new(5));

    let a = Rc::new(Cons(Rc::clone(&value), Rc::new(Nil)));

    let b = Cons(Rc::new(RefCell::new(3)), Rc::clone(&a));
    let c = Cons(Rc::new(RefCell::new(4)), Rc::clone(&a));
    
    match &b {
        Cons(x,y)=>{//line $
            match y.deref(){
                Cons(t,l)=>{
                    *t.borrow_mut() +=10;
                }
                _=>{}
            }
        }
        _=>{}
    }

    println!("a after = {:?}", a);
    println!("b after = {:?}", b);
    println!("c after = {:?}", c);
}

现在,考虑对 $ 行的以下更改:

//snip
  match &b {
        &Cons(x,y)=>{//a reference was added.
            match y.deref(){
//snip

这会导致以下错误:“error[E0507]: cannot move out of a shared reference”

我很困惑。似乎在那里添加引用应该阻止移动 - 而不是导致移动!

解释是什么?

Rust 链接列表 智能指针

评论

1赞 cafce25 9/26/2023
因为在模式取消引用中,它“匹配”了一个引用,就像在模式中匹配此构造函数一样。&Cons
0赞 violet 9/26/2023
这是有道理的。但是你说的“就像模式中的缺点匹配这个构造函数”是什么意思。
0赞 cafce25 9/26/2023
好吧,你在模式中编写,它“删除”了该构造函数并为您提供了它的参数,并且没有被包装,它删除了构造函数。Cons(x, y)xyConsCons
0赞 Cerberus 9/26/2023
对于这些情况,通常有用的链接 - h2co3.github.io/pattern

答:

3赞 drewtato 9/26/2023 #1

Rust 中添加了匹配人体工程学,以便更轻松地匹配引用。

当你写这样的东西时。

match &b {
    Cons(x, y) => {}
}

Rust 发现值的类型和模式的类型不匹配。它会自动将您的匹配转换为此匹配。&bCons(x, y)

match &b {
    &Cons(ref x, ref y) => {} // x is &Rc<RefCell<i32>, y is &Rc<List>
}

从本质上讲,它将绑定从具有所有权降级为引用。请记住,模式是减法的:任何不是绑定的东西都会从匹配值中移除。

let x = &Some(3); // x is &Option<i32>
let &x = &Some(3); // x is Option<i32>
let &Some(x) = &Some(3); // x is i32
let &Some(ref x) = &Some(3); // x is &i32

let Some(x) = &Some(3); // x is &i32 using match ergonomics

这里有更多关于 ref 关键字的信息。

你感到困惑的那个实际上是正常的。这里没有匹配的人体工程学,因为图案的类型和值匹配。

match &b {
    &Cons(x, y) => {} // x is Rc<RefCell<i32>>, y is Rc<List>
}

由于无法更改共享引用背后的值,因此除非 和 的类型为 Copy,否则不允许这样做。xy

评论

0赞 Sven Marnach 9/26/2023
我不认为 Rust 语言有任何单一的更改会生成与匹配“人体工程学”一样多的 StackOverflow 问题。