Rust能否自动获取值的不可变引用以匹配对应运算符实现?
解决方案
Rust 本身没有内置「运算符匹配失败时自动将值转为不可变引用」的语法机制,但可以通过泛型实现运算符自动转发,不需要重写运算逻辑,即可同时支持值类型和引用类型的运算调用。
核心思路
你已经为&Vec3实现了所有运算逻辑,只需额外增加一层泛型转发实现:利用Borrow<T> trait 可以同时匹配T和&T的特性,所有传入的运算数自动转成&Vec3后调用你已经写好的引用版本逻辑即可。
代码示例
原有引用实现(无需修改)
#[derive(Debug, Clone, Copy)] struct Vec3 { x: f32, y: f32, z: f32, } // 已有的&Vec3加法实现 impl std::ops::Add for &Vec3 { type Output = Vec3; fn add(self, rhs: Self) -> Self::Output { Vec3 { x: self.x + rhs.x, y: self.y + rhs.y, z: self.z + rhs.z, } } } // 已有的&Vec3减法实现 impl std::ops::Sub for &Vec3 { type Output = Vec3; fn sub(self, rhs: Self) -> Self::Output { Vec3 { x: self.x - rhs.x, y: self.y - rhs.y, z: self.z - rhs.z, } } } // 已有的&Vec3乘f32实现 impl std::ops::Mul<f32> for &Vec3 { type Output = Vec3; fn mul(self, rhs: f32) -> Self::Output { Vec3 { x: self.x * rhs, y: self.y * rhs, z: self.z * rhs, } } }
新增泛型转发实现
// 转发所有Vec3、&Vec3组合的加法调用 impl<T, U> std::ops::Add<U> for T where T: std::borrow::Borrow<Vec3>, U: std::borrow::Borrow<Vec3>, { type Output = Vec3; fn add(self, rhs: U) -> Self::Output { self.borrow() + rhs.borrow() } } // 转发所有Vec3、&Vec3组合的减法调用 impl<T, U> std::ops::Sub<U> for T where T: std::borrow::Borrow<Vec3>, U: std::borrow::Borrow<Vec3>, { type Output = Vec3; fn sub(self, rhs: U) -> Self::Output { self.borrow() - rhs.borrow() } } // 转发所有Vec3、&Vec3乘f32的调用 impl<T> std::ops::Mul<f32> for T where T: std::borrow::Borrow<Vec3>, { type Output = Vec3; fn mul(self, rhs: f32) -> Self::Output { self.borrow() * rhs } } // 可选:支持f32乘Vec3的交换律(即2.0 * v的写法) impl<T> std::ops::Mul<T> for f32 where T: std::borrow::Borrow<Vec3>, { type Output = Vec3; fn mul(self, rhs: T) -> Self::Output { rhs.borrow() * self } }
效果验证
完成上述实现后,以下写法都可以正常编译运行:
fn main() { let a = Vec3 { x: 1.0, y: 2.0, z: 3.0 }; let b = Vec3 { x: 4.0, y: 5.0, z: 6.0 }; // 所有组合都支持,无需手动加& let c = a + b; let d = &a + b; let e = a + &b; let f = &a + &b; let g = a * 2.0; let h = &a * 3.0; let i = 2.0 * a; }
简化方案
如果需要实现的运算符较多,也可以使用社区现成的宏库一键生成所有组合的转发实现,核心逻辑和上述手写实现完全一致。
内容的提问来源于stack exchange,提问作者Petr Broz
相关产品推荐
相关产品推荐

