2014-07-03 10 views
5

Ich versuche, einige allgemeine mathematische Funktionen in Rust zu schreiben, und ich halte in die folgende Fehlermeldung ausgeführt wird:Rust: Lösen Merkmal impl Konflikte

error: conflicting implementations for trait SoAndSo 

Ich möchte wissen, ob es möglich ist, das Problem zu lösen und wenn ja wie.

Zum Beispiel, ich versuche, ein generisches Punktprodukt zu schreiben, das zwei Iteratoren nimmt, reißt sie und iteriert über die Paare, um die Produkte zu akkumulieren. Aber ich möchte, dass diese Funktion auch komplexwertige Skalarprodukte berechnen kann. Das Skalarprodukt über komplexe Zahlen beinhaltet die Konjugation einer Seite. Meine erste Idee war, ein Merkmal Dot1 für eine binäre Funktion zu schreiben, um Mul darin zu ersetzen, dass es auch das Argument der linken Seite konjugiert. Hier ist der vollständige Code:

extern crate num; 

use num::complex::{Complex,Complex32,Complex64}; 
use std::num::Float; 

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

Da ein Complex<T> nicht Float, sollte es keine Überlappung betwen die beiden "generic impls". Daher erwarte ich keine Probleme. Aber jedes Mal wenn ich versuche, für ein Merkmal mehr als einen „generic impl“ zur Verfügung zu stellen, wird der Compiler mag es nicht:

<anon>:10:1: 12:2 error: conflicting implementations for trait `Dot1` 
<anon>:10 impl<T: Float> Dot1<T,T> for T { 
<anon>:11  fn dot1(&self, rhs: T) -> T { *self * rhs } 
<anon>:12 } 
<anon>:14:1: 16:2 note: note conflicting implementation here 
<anon>:14 impl<T: Num+Clone> Dot1<Complex<T>,Complex<T>> for Complex<T> { 
<anon>:15  fn dot1(&self, rhs: Complex<T>) -> Complex<T> { self.conj() * rhs } 
<anon>:16 } 
<anon>:14:1: 16:2 error: conflicting implementations for trait `Dot1` 
<anon>:14 impl<T: Num+Clone> Dot1<Complex<T>,Complex<T>> for Complex<T> { 
<anon>:15  fn dot1(&self, rhs: Complex<T>) -> Complex<T> { self.conj() * rhs } 
<anon>:16 } 
<anon>:10:1: 12:2 note: note conflicting implementation here 
<anon>:10 impl<T: Float> Dot1<T,T> for T { 
<anon>:11  fn dot1(&self, rhs: T) -> T { *self * rhs } 
<anon>:12 } 
<anon>:14:1: 16:2 error: failed to find an implementation of trait core::num::Float for num::complex::Complex<T> 
<anon>:14 impl<T: Num+Clone> Dot1<Complex<T>,Complex<T>> for Complex<T> { 
<anon>:15  fn dot1(&self, rhs: Complex<T>) -> Complex<T> { self.conj() * rhs } 
<anon>:16 } 

Wie kann ich einen generischen, Iterator-basierten Skalarprodukt schreiben, die für beiden Werke: real und komplexe Zahlen? Die Iteratoren zu nehmen, sie zu zippen, usw. ist kein Problem und ich konnte sogar herausfinden, welche Typparameter mit welchen Grenzen verwendet werden sollten. Aber ich bin nicht in der Lage, bestimmte Datentypen mit Merkmalen wie der oben genannten zu "vereinheitlichen".

+0

dies wird möglich sein, wenn [PR 48] (https://github.com/rust-lang/rfcs/pull/48) – Arjan

Antwort

2

Das Problem hier ist der (aktuelle) Compiler registriert nicht, Complex<T> implementiert nicht Float. Stellen Sie sich vor, Complex hätte Float implementiert: Entweder müsste es einen Weg geben, um zu entscheiden, welche impl zu verwenden ist, oder der überlappende Code müsste geächtet werden ... aber was ist, wenn jemand nur die impl<T> Float for Complex<T> in einer anderen Kiste hinzufügt der Compiler doesn ' Wissen Sie? Dieser letzte Punkt ist der Schlüssel: Im Gegensatz zu Haskell erlaubt das Design von Rust, dass dieser Code ohne Risiko völlig in Ordnung ist, alles nur deshalb, weil sich Rust darin unterscheidet, wie er mit dem letzten Punkt umgeht. Wenn Sie in einer Kiste, die Trait einen Typ Type und ein Merkmal sehen, dann wissen Sie 100% sicher, ob Type implementiert Trait: Rust nicht offene Welt Annahme Haskells haben, da Sie nur impl Trait for Type schreiben können, wenn entweder Trait oder Type Lüge in der aktuellen Kiste (Kompilationseinheit), das heißt, du kannst nicht orphan instances haben, wo jemand Float für Complex<T> in einer entfernten Kiste implementiert.

RFC 24 (das Chris verweist auf) recognises this, so dass diese generischen Implementierungen koexistieren mit spezifischeren, solange die Implementierungen garantiert nicht überlappen.

+0

implementiert Was ist 'Complex ' Sein "speziellere" als 'T'? Sollte das nicht für etwas zählen? Entschuldigung, aber was war der Grund, dieses Verhalten wieder aufzuheben, einschließlich der Überladungsauflösung à la C++? Bitte helfen Sie einem C++ - Programmierer, die Rust-Design-Entscheidungen zu verstehen. – sellibitze

+0

Es gibt keine Anerkennung der Spezialisierung in Rust (noch). Z.B. Sie müßten eine Möglichkeit haben, zu klären, welches 'impl' für '(uint, uint)' implizit verwendet wird. Merkmal für (uint, T) 'und' impl Merkmal für (T, uint) '.Philosophisch gesehen ist das System von Haskell ähnlich, und Sie müssen sich explizit für diese Art von "Impls" dort über Spracherweiterungen entscheiden, die Hauptprobleme dort gelten jedoch nicht notwendigerweise für Rust (dieselben wie die in dieser Antwort beschriebenen). . In der (langfristigen) Zukunft kann eine gewisse Form der "impl" -Spezifität hinzugefügt werden. – huon

Verwandte Themen