解决特质实施冲突

时间:2014-07-03 13:16:12

标签: generics traits rust

我正在尝试在Rust中编写一些通用数学函数,并且我一直遇到以下错误消息:

error: conflicting implementations for trait SoAndSo

有可能解决问题吗?如果是这样,怎么样?

例如,我正在尝试编写一个带有两个迭代器的通用点积,拉链它们并迭代它们以积累产品。我希望这个功能也能够计算复值点产品。复数上的点积包括共轭一侧。我的第一个想法是为二元函数写一个特征Dot1来替换Mul,因为它也会使左侧参数共轭。这是完整的代码:

extern crate num;

use num::complex::Complex;
use num::{Float, Num};

trait Dot1<Rhs, Result> {
    fn dot1(&self, rhs: Rhs) -> Result;
}

impl<T: Float> Dot1<T, T> for T {
    // conjugation for reals is a no-op
    fn dot1(&self, rhs: T) -> T {
        *self * rhs
    }
}

impl<T: Num + Clone> Dot1<Complex<T>, Complex<T>> for Complex<T> {
    fn dot1(&self, rhs: Complex<T>) -> Complex<T> {
        self.conj() * rhs
    }
}

fn main() {
    println!("Hello, world!")
}

由于Complex<T>不是Float,因此两个“通用推理”之间不应重叠。我没想到会出现任何问题,但每当我尝试为特征提供多个“通用impl”时,编译器都不喜欢它:

error[E0119]: conflicting implementations of trait `Dot1<num::Complex<_>, num::Complex<_>>` for type `num::Complex<_>`:
  --> src/main.rs:17:1
   |
10 | impl<T: Float> Dot1<T, T> for T {
   | ------------------------------- first implementation here
...
17 | impl<T: Num + Clone> Dot1<Complex<T>, Complex<T>> for Complex<T> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `num::Complex<_>`
   |
   = note: upstream crates may add new impl of trait `num::Float` for type `num::Complex<_>` in future versions

如何编写适用于实数和复数的通用,基于迭代器的点积?使用迭代器,压缩它们等不是问题,我甚至能够找出使用哪个类型参数与哪个边界。我似乎无法使用上面的特征“统一”某些数据类型。

1 个答案:

答案 0 :(得分:2)

这里的问题是(当前)编译器没有注册Complex<T>没有实现Float。想象一下,如果Complex确实实现了Float:要么必须有某种方式来决定使用哪个impl,要么重叠代码必须被取缔......但是如果有人怎么办?只在编译器不知道的其他一些包中添加impl<T> Float for Complex<T>

最后一点是关键:与Haskell不同,Rust的设计允许这些代码完全没有任何风险,因为Rust在处理最后一点方面有所不同。如果您在可以看到类型Type和特征Trait的箱子中,那么您知道100%确定Type是否实施Trait:Rust没有Haskell的开放世界假设,因为如果impl Trait for TypeTrait位于当前包(编译单元)中,您只能编写Type,也就是说,您不能拥有orphan instances },有人在某个遥远的箱子里为Float实施Complex<T>

RFC 24(Chris链接到)recognises this,允许这些通用实现与更具体的实现共存,只要保证实现不重叠。