我正在尝试创建一个可与各种原始数字类型一起使用的库,但我在使某些重载正常工作时遇到了一些麻烦。 (有关最小代码示例,请参阅附加的游乐场)
参见 E0210 和 E0117
我可以看到我的代码示例违反了 rust 的孤儿规则,但我不明白为什么在这种情况下这被认为是“坏事”。
看起来创建一个加号运算符将允许创建一个遵守交换规则的加号运算符,但是由于运算符重载固有的有序性质,我根本无法做到吗?
我想找到一种方法来获得反向加运算符重载(即允许
MyType + i32
和 i32 + MyType
都有效并且都返回 MyType。如果这是不可能的,那么我将不得不做出让步。
这篇关于堆栈溢出的文章似乎很好地解释了这个问题,并提供了一种有点有效的解决方法(因为它允许重载编译,但不允许反向运算符重载正确运行)
我看到here不可能解决这个问题,但我对这个结论既不自信也不感到惊讶。
#![allow(unused)]
use std::ops;
struct MyType {
val: i32,
}
trait SupportedType<T> {
fn as_my_type(val: T) -> MyType;
}
impl SupportedType<i32> for i32 {
fn as_my_type(val: Self) -> MyType {
MyType { val: val }
}
}
impl ops::Add<MyType> for MyType {
type Output = MyType;
fn add(self, val: MyType) -> Self::Output {
MyType { val: self.val + val.val }
}
}
// Works
impl<T: SupportedType<T>> ops::Add<T> for MyType where T: SupportedType<T> {
type Output = MyType;
fn add(self: MyType, val: T) -> Self::Output {
self + T::as_my_type(val)
}
}
// Doesn't work
impl<T: SupportedType<T>> ops::Add<MyType> for T where T: SupportedType<T> {
type Output = MyType;
fn add(self, val: T) -> Self::Output {
self + T::as_my_type(val)
}
}
fn main() {
let my_val: MyType = MyType { val: 42 };
let the_chosen_one: i32 = 21;
// Works: uses the first one
assert_eq!((my_val + the_chosen_one).val, 63);
// Doesn't work: uses the second one
assert_eq!((the_chosen_one + my_val).val, 63);
}
您只能使用具体类型来做到这一点。正如您所尝试的那样,一般来说这样做是不可能的。