[英]Overloading an operator for all structs with a trait in Rust
I'm trying to implement C++-style expression templates in Rust using traits and operator overloading.我正在尝试使用特征和运算符重载在 Rust 中实现 C++ 风格的表达式模板。 I'm getting stuck trying to overload '+' and '*' for every expression template struct.我在尝试为每个表达式模板结构重载 '+' 和 '*' 时陷入困境。 The compiler complains about the Add
and Mul
trait implementations:编译器抱怨Add
和Mul
trait 实现:
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
--> src/main.rs:32:6
|
32 | impl<T: HasValue + Copy, O: HasValue + Copy> Add<O> for T {
| ^ type parameter `T` must be used as the type parameter for some local type
|
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
= note: only traits defined in the current crate can be implemented for a type parameter
That error would make sense if the type I was trying to implement a trait for was constructible without my crate, but the type is a generic that must implement the HasValue
trait I defined.如果我尝试为其实现特征的类型无需我的 crate 即可构造,那么该错误是有意义的,但该类型是必须实现我定义的HasValue
特征的泛型。
Here's the code:这是代码:
use std::ops::{Add, Mul};
trait HasValue {
fn get_value(&self) -> i32;
}
// Val
struct Val {
value: i32,
}
impl HasValue for Val {
fn get_value(&self) -> i32 {
self.value
}
}
// Add
struct AddOp<T1: HasValue + Copy, T2: HasValue + Copy> {
lhs: T1,
rhs: T2,
}
impl<T1: HasValue + Copy, T2: HasValue + Copy> HasValue for AddOp<T1, T2> {
fn get_value(&self) -> i32 {
self.lhs.get_value() + self.rhs.get_value()
}
}
impl<T: HasValue + Copy, O: HasValue + Copy> Add<O> for T {
type Output = AddOp<T, O>;
fn add(&self, other: &O) -> AddOp<T, O> {
AddOp {
lhs: *self,
rhs: *other,
}
}
}
// Mul
struct MulOp<T1: HasValue + Copy, T2: HasValue + Copy> {
lhs: T1,
rhs: T2,
}
impl<T1: HasValue + Copy, T2: HasValue + Copy> HasValue for MulOp<T1, T2> {
fn get_value(&self) -> i32 {
self.lhs.get_value() * self.rhs.get_value()
}
}
impl<T: HasValue + Copy, O: HasValue + Copy> Mul<O> for T {
type Output = MulOp<T, O>;
fn mul(&self, other: &O) -> MulOp<T, O> {
MulOp {
lhs: *self,
rhs: *other,
}
}
}
fn main() {
let a = Val { value: 1 };
let b = Val { value: 2 };
let c = Val { value: 2 };
let e = ((a + b) * c).get_value();
print!("{}", e);
}
Thoughts?想法?
Trying to define the trait Add
for you custom types, you are doing this:尝试为您的自定义类型定义特征Add
,您正在这样做:
impl<T: HasValue + Copy, O: HasValue + Copy> Add<O> for T {
type Output = AddOp<T, O>;
fn add(&self, other: &O) -> AddOp<T, O> {
AddOp {
lhs: *self,
rhs: *other,
}
}
}
But T: HasValue + Copy
matches any type implementing trait HasValue
, and this type may not be defined in your crate (for example if you implement HasValue
for i32
).但是T: HasValue + Copy
匹配任何实现 trait HasValue
类型,并且这个类型可能没有在你的箱子中定义(例如,如果你为i32
实现HasValue
)。 As Add
isn't defined in your crate either, Rust complains: for example by defining HasValue
for i32
, you would also re-define Add<i32>
for i32
!由于Add
未在箱子定义要么,防锈抱怨:例如通过定义HasValue
为i32
,也将重新定义Add<i32>
为i32
!
My suggestion would be to wrap all your operation and values structs into a generic one, and implementing Add
and Mul
for it.我的建议是将所有操作和值结构包装成一个通用结构,并为其实现Add
和Mul
。 This way, you implement Add
and Mul
only for a simple type defined in your crate, and the compiler is happy.这样,您只为在 crate 中定义的简单类型实现Add
和Mul
,编译器很高兴。
Something like that:类似的东西:
struct Calculus<T> {
calc: T,
}
impl<T: HasValue + Copy> HasValue for Calculus<T> {
fn get_value(&self) -> i32 {
self.calc.get_value()
}
}
impl<T, O> Add<Calculus<O>> for Calculus<T>
where
T: HasValue + Copy,
O: HasValue + Copy,
{
type Output = Calculus<AddOp<T, O>>;
fn add(self, other: Calculus<O>) -> Calculus<AddOp<T, O>> {
Calculus {
calc: AddOp {
lhs: self.calc,
rhs: other.calc,
},
}
}
}
impl<T, O> Mul<Calculus<O>> for Calculus<T>
where
T: HasValue + Copy,
O: HasValue + Copy,
{
type Output = Calculus<MulOp<T, O>>;
fn mul(self, other: Calculus<O>) -> Calculus<MulOp<T, O>> {
Calculus {
calc: MulOp {
lhs: self.calc,
rhs: other.calc,
},
}
}
}
Then you can just add a neat new()
method for your Val
type:然后你可以为你的Val
类型添加一个简洁的new()
方法:
impl Val {
fn new(n: i32) -> Calculus<Val> {
Calculus {
calc: Val { value: n },
}
}
}
and use the whole thing like this:并像这样使用整个东西:
fn main() {
let a = Val::new(1);
let b = Val::new(2);
let c = Val::new(3);
let e = ((a + b) * c).get_value();
print!("{}", e);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.