Rust引用模式中双、单引用的行为差异原因探究
Rust引用模式的可变场景行为差异解析
在Rust的模式匹配中,我们可以在标识符前添加&、&&、&mut等前缀,比如v.iter().filter(|&e| ...)里的&e,这被称为引用模式(reference patterns)。
实际使用中会发现一种不一致的行为:
- 处理双重不可变借用的值时,
&&e和&e两种模式都能正常工作 - 但处理可变借用的场景时,
&&mut e可以正常使用,&mut e却会编译报错
核心原因:闭包参数的类型与模式匹配的兼容性
要理解这个差异,得先明确迭代器返回的元素类型,以及filter闭包接收的参数类型:
- 不可变迭代(
iter())的情况v.iter()返回的迭代器,每个元素的类型是&i32(不可变引用)。而filter方法的闭包参数是对迭代器元素的引用,也就是&&i32(不可变引用嵌套不可变引用)。
- 当使用
&e模式时:外层的&会匹配&&i32的外层不可变引用,将内层的&i32绑定到e。因为不可变引用实现了Copytrait,这种匹配是允许的。 - 当使用
&&e模式时:两层&分别匹配&&i32的两层引用,直接将底层的i32值绑定到e,同样合法。
- 可变迭代(
iter_mut())的情况v.iter_mut()返回的迭代器,每个元素的类型是&mut i32(可变引用)。对应filter闭包的参数是&(&mut i32)——也就是不可变引用指向可变引用。
- 当尝试使用
&mut e模式时:这个模式要求匹配的是一个&mut _类型的可变引用,但闭包参数实际是不可变的&(&mut i32),类型不匹配,因此编译报错。 - 当使用
&&mut e模式时:外层的&先匹配闭包参数的不可变引用,内层的&mut e再匹配底层的&mut i32可变引用,最终将i32值绑定到e,类型匹配,所以可以正常工作。
示例代码验证
fn main() { let mut v = vec![1, 2, 3, 4, 5]; // 不可变迭代:filter参数是&&i32 v.iter() .filter(|e| *e * 2 >= 8) // e是&&i32,*e得到&i32 .for_each(|e| println!("{}", e)); v.iter() .filter(|e| **e * 2 >= 8) // **e直接得到i32 .for_each(|e| println!("{}", e)); v.iter() .filter(|&e| e * 2 >= 8) // e是&i32,匹配外层& .for_each(|e| println!("{}", e)); v.iter() .filter(|&&e| e * 2 >= 8) // e是i32,匹配两层& .for_each(|e| println!("{}", e)); // 编译错误:&mut e模式无法匹配不可变的&&mut i32 // v.iter_mut() // .filter(|&mut e| e * 2 >= 8) // .for_each(|e| println!("{}", e)); // 可变迭代:filter参数是&&mut i32,&&mut e匹配两层引用 v.iter_mut() .filter(|&&mut e| e * 2 >= 8) .for_each(|e| println!("{}", e)); }
内容的提问来源于stack exchange,提问作者ynn
相关产品推荐
相关产品推荐

