获取以下代码
let t : &&mut (&str, u8) = &&mut ("hallo", 1u8);
let (n, a) = t;
例如,t
可以是 .iter_mut().find()
闭包中的输入。
Rust 分析器和编译器将分配
n
类型 &&str
和 a
类型 &u8
我的问题是为什么。一级间接指向哪里?我本来希望
n
具有类型 &&mut &str
。
正如评论中所建议的,匹配人体工程学是在模式匹配表达式“
let (n, a) = t;
”中发挥作用的。
编译器做了一些假设,并在某种程度上简化了匹配的引用。下面的代码通过一些极端的方式来说明这种行为。下面的输出显示了对引用的最终影响。
fn typestr<T>(_: &T) -> &str { std::any::type_name::<T>() }
macro_rules! print_type {
( $($t: expr),* ) => {{
$( print!("{}: {:<12}", stringify!($t), typestr(&$t)); )* println!();
}}
}
fn main() {
let t : &mut (&str, u8) = &mut ("hallo", 1u8);
let (n, a) = t;
print_type!(n, a, t);
let t : &&mut (&str, u8) = &&mut ("hallo", 1u8);
let (n, a) = t;
print_type!(n, a, t);
let t : &&&&mut (&str, u8) = &&&&mut ("hallo", 1u8);
let (n, a) = t;
print_type!(n, a, t);
let t : &mut &mut &mut &mut &mut (&str, u8) =
&mut &mut &mut &mut &mut ("hallo", 1u8);
let (n, a) = t;
print_type!(n, a, t);
}
n: &mut &str a: &mut u8 t: &mut (&str, u8)
n: &&str a: &u8 t: &&mut (&str, u8)
n: &&str a: &u8 t: &mut &&&mut (&str, u8)
n: &mut &str a: &mut u8 t: &mut &mut &mut &mut &mut (&str, u8)
可以看出,第二个和第三个示例的解除引用已进行了一定程度的调整。输出的最后一行显示了如何为多个可变间接保留可变性。技巧是
&mut
需要应用于每个引用运算符。否则,可变性就会丢失。
上面链接的 RFC 中的此图显示了如何执行自动参考调整:
Start
|
v
+-----------------------+
| Default Binding Mode: |
| move |
+-----------------------+
/ \
Encountered / \ Encountered
&mut val / \ &val
v v
+-----------------------+ +-----------------------+
| Default Binding Mode: | | Default Binding Mode: |
| ref mut | | ref |
+-----------------------+ +-----------------------+
----->
Encountered
&val
因为在OP的示例中,只有第二个引用是可变的(
&&mut
),而第一个引用不是,所以在解构赋值时可变性丢失了。