编译如下:
#[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
这会导致以下错误:“错误[E0507]:无法移出共享引用”
我很困惑。似乎在那里添加引用应该防止移动 - 而不是导致移动!
解释是什么?
匹配人体工程学,以便更轻松地匹配参考。
当你写下这样的东西时。
match &b {
Cons(x, y) => {}
}
Rust 发现值
&b
的类型与模式 Cons(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>
}
并且由于您无法更改共享引用背后的值,因此不允许这样做,除非
x
和 y
的类型是 Copy
。