为何Rust示例中`ref`会导致字段被解引用?
ref反而能让代码编译? 先拆解问题里的核心逻辑:你的代码里匹配的是可变引用&mut Thing,模式匹配的行为在面对引用类型时,和匹配值类型的规则不一样,这是关键。
1. 不加ref时的问题
当你写if let Thing::A { value } = thing_mut_ref时,thing_mut_ref是&mut Thing类型。Rust的模式匹配在处理可变引用时,会自动为字段创建可变引用绑定——也就是说value的类型是&mut f32。
而标准库中并没有为&mut f32和f32实现乘法(Mul trait),所以直接写value * 2.0会报错:编译器不知道怎么把可变引用和浮点数相乘。这时候你如果改成*value * 2.0,手动解引用可变引用为f32,代码也能正常编译。
2. 加ref后的变化
当你在模式里加上ref,写成if let Thing::A { ref value } = thing_mut_ref时,ref关键字改变了绑定的类型:原本会绑定&mut f32,现在ref告诉Rust:“我要的是这个字段的共享引用”,也就是value的类型变成了&f32。
而标准库为&f32和f32实现了Mul trait,编译器会自动解引用&f32为f32来执行乘法运算,所以value * 2.0能正常编译。
3. 关于ref的“反向”直觉
你觉得ref是“不希望按值捕获”,这个理解没错——但那是针对匹配值类型的场景。比如当你匹配Thing类型(不是引用)时,Thing::A { value }会按值捕获f32,而Thing::A { ref value }会捕获&f32。
但当你匹配的是引用类型(比如&mut Thing)时,默认的绑定已经是引用了,这时候ref的作用是把可变引用转换成共享引用,而不是从值转成引用——这就是为什么看起来和直觉相反的原因。
替代写法
除了加ref,你也可以手动解引用可变引用,或者先解引用整个thing_mut_ref再匹配:
// 手动解引用可变引用 if let Thing::A { value } = thing_mut_ref { *thing_mut_ref = Thing::B { value: *value * 2.0 }; } // 先解引用整个可变引用再匹配 if let Thing::A { value } = &mut *thing_mut_ref { *thing_mut_ref = Thing::B { value: *value * 2.0 }; }
内容的提问来源于stack exchange,提问作者Alex Hastings

