簡體   English   中英

在 Rust 中為所有具有特征的結構重載運算符

[英]Overloading an operator for all structs with a trait in Rust

我正在嘗試使用特征和運算符重載在 Rust 中實現 C++ 風格的表達式模板。 我在嘗試為每個表達式模板結構重載 '+' 和 '*' 時陷入困境。 編譯器抱怨AddMul 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

如果我嘗試為其實現特征的類型無需我的 crate 即可構造,那么該錯誤是有意義的,但該類型是必須實現我定義的HasValue特征的泛型。

這是代碼:

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);
}

想法?

嘗試為您的自定義類型定義特征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,
        }
    }
}

但是T: HasValue + Copy匹配任何實現 trait HasValue類型,並且這個類型可能沒有在你的箱子中定義(例如,如果你為i32實現HasValue )。 由於Add未在箱子定義要么,防銹抱怨:例如通過定義HasValuei32 ,也將重新定義Add<i32>i32

我的建議是將所有操作和值結構包裝成一個通用結構,並為其實現AddMul 這樣,您只為在 crate 中定義的簡單類型實現AddMul ,編譯器很高興。

類似的東西:

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,
            },
        }
    }
}

然后你可以為你的Val類型添加一個簡潔的new()方法:

impl Val {
    fn new(n: i32) -> Calculus<Val> {
        Calculus {
            calc: Val { value: n },
        }
    }
}

並像這樣使用整個東西:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM