Rust RFC2005 match ergonomics下单个&模式为何两次解引用
关于match ergonomics模式匹配中单个
&触发两次解引用的解释 问题背景
依据RFC 2005定义的match ergonomics规则,很多开发者会遇到一个反直觉的现象:引用模式中只写单个&时,看似会对被匹配值执行两次解引用操作。
示例场景
假设存在map: HashMap<i32, bool>,考虑表达式map.iter().filter(|entry| ...),其中闭包参数entry的类型为&(&i32, &bool)。我们用两种模式匹配entry,得到的绑定类型完全不同:
map .iter() .filter(|entry| { let (key1, _) = entry; // key1类型为&&i32 let (&key2, _) = entry; // key2类型为i32 })
直觉上两种模式都是用非引用模式匹配指向元组的引用,默认绑定模式会切换为ref,但key2最终类型是i32而非预期的&i32。不少人推导的脱糖形式会出现错误:
// key1的脱糖是正确的,key1_desugared类型为&&i32 let &(ref key1_desugared, _) = entry; // 错误脱糖,推导得到key2_desugared类型为&i32,和实际结果不符 let &(& ref key2_desugared, _) = entry;
规则拆解与正确脱糖
要搞清楚这个差异,必须先明确RFC 2005的两个核心匹配逻辑:
- 当非引用模式匹配到引用类型值时,编译器会自动解引用该值,同时将当前作用域的默认绑定模式切换为
ref(即自动给绑定加引用) - 当模式中出现**显式
&**时,编译器会解引用对应位置的值,后续子模式的匹配会重置默认绑定模式为初始的move(按值绑定),直到再次遇到非引用模式匹配引用值才会切回ref
我们逐步骤拆解两个匹配的执行流程:
匹配
let (key1, _) = entry- 被匹配值
entry是&(&i32, &bool)类型的引用,最外层的元组模式属于非引用模式,因此编译器自动解引用外层引用,拿到内部元组(&i32, &bool),同时默认绑定模式切换为ref - 匹配元组第一个元素(类型为
&i32)时,直接用默认ref模式绑定key1,因此key1类型为&&i32,对应脱糖形式和推导一致。
- 被匹配值
匹配
let (&key2, _) = entry- 第一步和上述流程完全一致:最外层元组模式匹配
entry引用,自动解引用拿到元组,默认绑定模式切换为ref - 匹配元组第一个元素时,模式写了显式
&:编译器先解引用该位置的&i32拿到内部i32值,同时将该子模式内的默认绑定模式重置为move - 绑定
key2时使用当前的move模式,直接绑定解引用得到的i32值,因此key2类型为i32 - 对应的正确脱糖形式为
let &(ref &key2, _) = entry;——自动添加的ref作用在显式&模式外层,而非绑定变量前。
- 第一步和上述流程完全一致:最外层元组模式匹配
所谓“单个&触发两次解引用”本质是两次解引用的来源不同:第一次是match ergonomics自动为最外层非引用模式解的entry外层引用,第二次是显式&解的元组元素引用,两次解引用叠加才造成了“一个&解两层”的错觉。
验证方式
上述结论可以直接在稳定版Rust编译器中通过类型标注验证,无需额外依赖。
内容的提问来源于stack exchange,提问作者mxxk
相关产品推荐
相关产品推荐

