Rust中实现可同时返回可变与不可变引用的通用逻辑的问题
Rust中实现可同时返回可变与不可变引用的通用逻辑的问题
嘿,我刚接触Rust没多久,最近碰到了个挺典型的问题,想跟大家请教下。我写了个结构体,里面有两个同类型的向量字段:first: Vec<u32>和second: Vec<u32>。现在我想根据结构体里switch字段的值,让sum(需要读取向量,用不可变引用)和push(需要修改向量,用可变引用)这两个方法分别操作其中一个向量。
我本来想着把判断switch的逻辑抽出来写个叫get_vector的辅助方法,这样sum和push就不用重复写相同的判断了,但问题来了:sum需要的是不可变引用,push需要的是可变引用,怎么让这个辅助方法既能返回不可变引用,又能返回可变引用呢?总不能写两个几乎一模一样的方法吧?
举个我的代码例子:
struct MyStruct { first: Vec<u32>, second: Vec<u32>, switch: bool, } impl MyStruct { // 这个方法只能返回不可变引用,push用不了 fn get_vector(&self) -> &Vec<u32> { if self.switch { &self.first } else { &self.second } } fn sum(&self) -> u32 { self.get_vector().iter().sum() } fn push(&mut self, val: u32) { // 这里需要&mut Vec<u32>,但get_vector给不了,咋办? // self.get_vector().push(val); 这行肯定编译不过 } }
可行的解决方案
其实在Rust的生态里,这种场景的标准做法就是提供一对对应的方法:一个返回不可变引用,一个返回可变引用——也就是大家常看到的get_xxx和get_xxx_mut模式。如果担心判断逻辑重复,可以把核心的判断逻辑抽成私有辅助函数,再在两个对外方法里调用它,这样就不用写两遍判断了:
struct MyStruct { first: Vec<u32>, second: Vec<u32>, switch: bool, } impl MyStruct { // 私有辅助:处理判断,返回不可变引用 fn target_vector(&self) -> &Vec<u32> { if self.switch { &self.first } else { &self.second } } // 私有辅助:处理判断,返回可变引用 fn target_vector_mut(&mut self) -> &mut Vec<u32> { if self.switch { &mut self.first } else { &mut self.second } } // 对外的不可变访问方法 pub fn get_vector(&self) -> &Vec<u32> { self.target_vector() } // 对外的可变访问方法 pub fn get_vector_mut(&mut self) -> &mut Vec<u32> { self.target_vector_mut() } pub fn sum(&self) -> u32 { self.target_vector().iter().sum() } pub fn push(&mut self, val: u32) { self.target_vector_mut().push(val); } }
为什么不能用一个方法搞定?
这其实是Rust静态类型系统和借用规则的限制:
- 方法的返回类型必须是确定的,你没法让一个方法有时候返回
&Vec<u32>,有时候返回&mut Vec<u32>——静态类型要求编译期就确定返回类型。 - 从借用规则来说,可变引用和不可变引用是互斥的,同一个方法返回两种引用会直接违反Rust的内存安全保证,编译器肯定会拦着你。
如果你的判断逻辑特别复杂,不想写两遍辅助函数,理论上可以用unsafe代码绕过借用检查,但非常不推荐——这会把Rust最核心的内存安全保障丢掉,很容易引发悬垂引用或者数据竞争的问题。
备注:内容来源于stack exchange,提问作者jjoelson
相关产品推荐
相关产品推荐

