You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust引用模式中双、单引用的行为差异原因探究

Rust引用模式的可变场景行为差异解析

在Rust的模式匹配中,我们可以在标识符前添加&、&&、&mut等前缀,比如v.iter().filter(|&e| ...)里的&e,这被称为引用模式(reference patterns)。

实际使用中会发现一种不一致的行为:

  • 处理双重不可变借用的值时,&&e和&e两种模式都能正常工作
  • 但处理可变借用的场景时,&&mut e可以正常使用,&mut e却会编译报错

核心原因:闭包参数的类型与模式匹配的兼容性

要理解这个差异,得先明确迭代器返回的元素类型,以及filter闭包接收的参数类型:

  1. 不可变迭代(iter())的情况
    v.iter()返回的迭代器,每个元素的类型是&i32(不可变引用)。而filter方法的闭包参数是对迭代器元素的引用,也就是&&i32(不可变引用嵌套不可变引用)。
  • 当使用&e模式时:外层的&会匹配&&i32的外层不可变引用,将内层的&i32绑定到e。因为不可变引用实现了Copy trait,这种匹配是允许的。
  • 当使用&&e模式时:两层&分别匹配&&i32的两层引用,直接将底层的i32值绑定到e,同样合法。
  1. 可变迭代(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 21:45:36