请使用以下代码
let t : &&mut (&str, u8) = &&mut ("hallo", 1u8);
let (n, a) = t;
例如,t
可以是.iter_mut().find()
闭包中的输入.
铁 rust 分析器和编译器将把类型&&str
赋值n
,将类型&u8
赋值a
我的问题是为什么.一个级别的间接会走向何方?我本以为n
会是&&mut &str
型.
请使用以下代码
let t : &&mut (&str, u8) = &&mut ("hallo", 1u8);
let (n, a) = t;
例如,t
可以是.iter_mut().find()
闭包中的输入.
铁 rust 分析器和编译器将把类型&&str
赋值n
,将类型&u8
赋值a
我的问题是为什么.一个级别的间接会走向何方?我本以为n
会是&&mut &str
型.
正如注释中所建议的那样,match ergonomics是模式匹配表达式"let (n, a) = t;
"中起作用的内容.或者,更具体地说,正在应用"绑定模式规则".
编译器做了一些假设,并在一定程度上简化了匹配的引用.下面的代码(playground)使用了一些极端的方式来说明这种行为.下面的输出显示了引用的最终效果.
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);// <- t declared with type spec.
let (n, a) = t; // <- destructuring assignment.
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);
}
Output:
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
),而第一个引用不是,所以在析构赋值时会丢失可变性.