解决特质实施冲突 [英] Resolving trait implementation conflicts

查看:109
本文介绍了解决特质实施冲突的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在Rust中编写一些通用的数学函数,并且一直运行到以下错误消息:

 错误:特征冲突的实现SoAndSo 

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

例如,我试图编写一个通用点产品,它需要两个迭代器,将它们压缩并遍历这些对以累积产品。我希望这个函数也能够计算复数点的产品。复数的点积涉及到一边的共轭。我的第一个想法是为二元函数编写 Dot1 来替换 Mul ,因为它也将左手方参数。这是完整的代码:

  extern crate num; 

使用num :: complex :: Complex;
使用num :: {Float,Num};

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

impl< T:Float> Dot1< T,T>对于T {
//对于实数的共轭是一个无操作
fn dot1(& self,rhs:T) - > T {
* self * rhs
}
}

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

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





由于 Complex< T> 不是 Float ,两个通用impls之间不应该有重叠。我没有想到任何问题,但每次我尝试为特征提供多个通用impl时,编译器都不喜欢它:

 错误[E0119]:类型为`num:'的特征`Dot1< num :: Complex< _>,num :: Complex<> :Complex< _>:
- > src / main.rs:17:1
|
10 | impl< T:Float> Dot1< T,T>为T {
| -------------------------------首先在这里执行
...
17 | impl< T:Num +克隆> Dot1< Complex< T>,Complex< T>对于Complex< T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `num :: Complex< _>`
|的冲突实现^^^^^^^^^^^^^^
= note:在未来的版本中,上游箱子可以为`num :: Complex< _> ;,类型添加新的特征'num :: Float'的impl

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

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

最后一点是关键:与Haskell不同,Rust's设计允许此代码完全没有任何风险,因为Rust在处理最后一点时有所不同。如果你在一个可以看到类型类型和特征特征的箱子中,那么你知道100%肯定如果类型实现 Trait :Rust没有Haskell的开放世界假设,因为你只能写<$ c $如果 Trait 类型位于当前文件夹中,则c> impl类型为编译单元),也就是说,您不能拥有孤儿实例,其中某个人实现了<$ c

RFC中的$ c> Float 用于复杂的< T> 。 24(克里斯链接)认识到这一点,允许这些泛型实现与更具体的实现共存,只要实现保证不重叠即可。


I'm trying to write some generic math functions in Rust and I keep running into the following error message:

error: conflicting implementations for trait SoAndSo

Is it possible to solve the problem? If so, how?

For example, I'm trying to write a generic dot product that takes two iterators, zips them and iterates over the pairs to accumulate the products. I want this function also to be able to compute complex-valued dot products. The dot product over complex numbers involves conjugating one side. My first idea was to write a trait Dot1 for a binary function to replace Mul in that it also conjugates the left hand side argument. Here's the complete code:

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!")
}

Since a Complex<T> is not Float, there should be no overlap between the two "generic impls". I didn't expect any problems, but every time I try to provide more than one "generic impl" for a trait, the compiler doesn't like it:

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

How can I write a generic, iterator-based dot product that works for both real and complex numbers? Taking the iterators, zipping them, etc. is not a problem and I was even able to figure out what type parameters to use with which bounds. I don't seem able to "unify" certain data types using traits such as the one from above.

解决方案

The problem here is the (current) compiler does not register that Complex<T> does not implement Float. Imagine if Complex did implement Float: either there would have to be some way to decide which impl to use, or the overlapping code would have to be outlawed... but what if someone only adds the impl<T> Float for Complex<T> in some other crate the compiler doesn't know about?

This last point is key: unlike Haskell, Rust's design allows this code to be perfectly OK without any risk, all because Rust differs in how it handles the last point. If you are in a crate that can see a type Type and a trait Trait, then you know for 100% sure if Type implements Trait: Rust doesn't have Haskell's open world assumption, as you can only write impl Trait for Type if either Trait or Type lie in the current crate (compilation unit), that is, you can't have orphan instances, where someone implements Float for Complex<T> in some distant crate.

RFC 24 (that Chris links to) recognises this, allowing these generic implementations to coexist with more specific ones, as long as the implementations are guaranteed to not overlap.

这篇关于解决特质实施冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆