Rust中同类型的同一trait出现多个实现

4

使用 Rust trait,我可以表达一个 Monoid 类型类(请原谅我取的方法名):

trait Monoid {
  fn append(self, other: Self) -> Self;
  fn neutral() -> Self;
}

那么,我也可以为字符串或整数实现该特性:

impl Monoid for i32 {
  fn append(self, other: i32) -> i32 {
    self + other
  }
  fn neutral() -> Self { 0 }
}

但是,我现在该如何为乘法情况添加另一个关于 i32 的实现呢?

impl Monoid for i32 {
  fn append(self, other: i32) -> i32 {
    self * other
  }
  fn neutral() { 1 }
}

我尝试了类似于functional中所做的内容,但是那个解决方案似乎依赖于在trait上有一个额外的类型参数,而不是使用Self来表示元素,这会给我一个警告。

首选的解决方案将是使用标记trait来进行操作 - 我也尝试过,但没有成功。


13
我不明白这应该代表什么意思。如果两个实现具有完全相同的签名,编译器该如何猜测你想要哪个实现? - Félix Adriyel Gagnon-Grenier
你说得对。我想找出是否有一种方法可以使用类似标记特征的东西作为附加类型参数或类似的东西,让编译器区分这两种情况。 - Yann
@Yann,关于我的帖子:是的,但是使用trait约束的情况不同。因为一个类型只能实现其中之一。Trait约束应该足以让他意识到这是两个不同的实现。如果一个类型同时实现了mul和add,那么你可以在使用时明确地消除歧义...我不知道为什么它不能推断出它们是两个不同的实现。 - Netwave
2
你可以使用标记类型,例如在这个playground中。这是你想要的吗? - rodrigo
@rodrigo 太棒了,看起来非常像我想要的。我还可以添加一个共同的特征 Op,让两个操作结构都实现它(这里)。谢谢! - Yann
2
@Yann:不错!现在你有一个可用的代码了,随意回答(并最终接受)你自己的问题。 - rodrigo
1个回答

7

正如@rodrigo所指出的那样,答案是使用标记结构体

以下示例展示了一个完整的代码片段:playground

trait Op {}
struct Add;
struct Mul;
impl Op for Add {}
impl Op for Mul {}

trait Monoid<T: Op>: Copy {
    fn append(self, other: Self) -> Self;
    fn neutral() -> Self;
}

impl Monoid<Add> for i32 {
    fn append(self, other: i32) -> i32 {
        self + other
    }
    fn neutral() -> Self {
        0
    }
}

impl Monoid<Mul> for i32 {
    fn append(self, other: i32) -> i32 {
        self * other
    }
    fn neutral() -> Self {
        1
    }
}

pub enum List<T> {
    Nil,
    Cons(T, Box<List<T>>),
}

fn combine<O: Op, T: Monoid<O>>(l: &List<T>) -> T {
    match l {
        List::Nil => <T as Monoid<O>>::neutral(),
        List::Cons(h, t) => h.append(combine(&*t)),
    }
}

fn main() {
    let list = List::Cons(
        5,
        Box::new(List::Cons(
            2,
            Box::new(List::Cons(
                4,
                Box::new(List::Cons(
                    5,
                    Box::new(List::Cons(-1, Box::new(List::Cons(8, Box::new(List::Nil))))),
                )),
            )),
        )),
    );
    
    println!("{}", combine::<Add, _>(&list));
    println!("{}", combine::<Mul, _>(&list))
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接