2014-07-06 2 views
16

die folgende Struktur gegeben:Wie kann ein Bediener für verschiedene RHS-Typen und Rückgabewerte überlastet werden?

struct Vector3D { 
    x: f32, 
    y: f32, 
    z: f32 
} 

Ich möchte seine * Betreiber zu überlasten ein Punktprodukt zu tun, wenn die rechte Seite ein Vector3D ist, und ein Element weise Multiplikation zu tun, wenn die rechte Seite ein f32 ist. Mein Code sieht wie folgt aus:

// Multiplication with scalar 
impl Mul<f32, Vector3D> for Vector3D { 
    fn mul(&self, f: &f32) -> Vector3D { 
     Vector3D {x: self.x * *f, y: self.y * *f, z: self.z * *f} 
    } 
} 
// Multiplication with vector, aka dot product 
impl Mul<Vector3D, f32> for Vector3D { 
    fn mul(&self, other: &Vector3D) -> f32 { 
     self.x * other.x + self.y * other.y + self.z * other.z 
    } 
} 

Der Compiler sagt zum ersten impl Block:

Vector3D.rs:40:1: 44:2 error: conflicting implementations for trait `std::ops::Mul` 
Vector3D.rs:40 impl Mul<f32, Vector3D> for Vector3D { 
... 
Vector3D.rs:53:1: 57:2 note: note conflicting implementation here 
Vector3D.rs:53 impl Mul<Vector3D, f32> for Vector3D { 
... 

und umgekehrt für die andere Implementierung.

+0

Dies ist ein Duplikat von http://stackoverflow.com/questions/24554738/rust-resolving-trait-impl-conflicts. –

+0

@ChrisMorgan ist es nicht wirklich ein Duplikat. Diese Frage hat zwei konkrete "Impls", während diese Frage einen generischen "impl" zusammen mit einem konkreten "impl" hat. – huon

Antwort

11

Im Moment ist pro Merkmalspaar nur eine einzige impl zulässig.

Diese Situation wird verbessert mit RFC 48 sein, aber es ist nicht die ganze Geschichte (es ist nicht wirklich etwas von der Geschichte). Der entsprechende Abschnitt ist Coherence, und es ist sicherlich nicht der Betreiber Überlastung Fall ausdrücklich erwähnt, und im Wesentlichen sagt es immer noch illegal ist:

Das folgende Beispiel ist nicht in Ordnung:

trait Iterator<E> { ... } 
impl Iterator<char> for ~str { ... } 
impl Iterator<u8> for ~str { ... } 

Niko Matsakis (Autor des RFC & Rust-Typ-System-Experte) hat über diese Überlastung Merkmale speziell gedacht: Er ist derjenige, der published ("Was ist, wenn ich will überladen?") Den Trick unten, aber er hat seine Abneigung ausgedrückt gegenüber es, Erwähnung, dass er gerne implementieren würde Entsprechungen, wie Sie geschrieben haben ...

... wo ist seine RFC 135 kommt in. Die Situation wird ausführlich in "multidispatch traits" beschrieben.


Sie können es jetzt mit sekundären Merkmalen umgehen. Die zusätzliche Ebene der Merkmale ermöglicht es Ihnen, nur eine impl Mul<...> for Vector3D zu schreiben, kostet Sie aber ein neues Merkmal für jeden Typ, für den Sie mehrere Implementierungen von Mul haben möchten.

#[deriving(Show)] 
struct Vector3D { 
    x: f32, 
    y: f32, 
    z: f32 
} 

trait MulVec3D<Res> { 
    fn do_mul(&self, v: &Vector3D) -> Res; 
} 

// Multiplication with scalar 
impl MulVec3D<Vector3D> for f32 { 
    fn do_mul(&self, v: &Vector3D) -> Vector3D { 
     Vector3D {x: v.x * *self, y: v.y * *self, z: v.z * *self} 
    } 
} 
// Multiplication with vector, aka dot product 
impl MulVec3D<f32> for Vector3D { 
    fn do_mul(&self, v: &Vector3D) -> f32 { 
     self.x * v.x + self.y * v.y + self.z * v.z 
    } 
} 

impl<Res, RHS: MulVec3D<Res>> Mul<RHS, Res> for Vector3D { 
    fn mul(&self, rhs: &RHS) -> Res { 
     rhs.do_mul(self) 
    } 
} 

fn main() { 
    let a = Vector3D { x: 1.0, y: 2.0, z: 3.0 }; 
    let b = Vector3D { x: -3.0, y: 2.0, z: -1.0 }; 

    println!("{}, {}", a * 2f32, a * b); // Vector3D { x: 2, y: 4, z: 6 }, -2 
} 
+0

Diese Lösung scheint veraltet zu sein und gibt Compilerfehler. Shepmasters Antwort scheint der Rechnung zu entsprechen. – progician

25

Ab Rust 1.0 können Sie jetzt diese implementieren:

use std::ops::Mul; 

#[derive(Copy, Clone, PartialEq, Debug)] 
struct Vector3D { 
    x: f32, 
    y: f32, 
    z: f32, 
} 

// Multiplication with scalar 
impl Mul<f32> for Vector3D { 
    type Output = Vector3D; 

    fn mul(self, f: f32) -> Vector3D { 
     Vector3D { 
      x: self.x * f, 
      y: self.y * f, 
      z: self.z * f, 
     } 
    } 
} 

// Multiplication with vector, aka dot product 
impl Mul<Vector3D> for Vector3D { 
    type Output = f32; 

    fn mul(self, other: Vector3D) -> f32 { 
     self.x * other.x + self.y * other.y + self.z * other.z 
    } 
} 

fn main() { 
    let a = Vector3D { 
     x: 1.0, 
     y: 2.0, 
     z: 3.0, 
    }; 
    let b = a * -1.0; 
    let c = a * b; 

    println!("{:?}", a); 
    println!("{:?}", b); 
    println!("{:?}", c); 
} 

Die große Veränderung, die dies ermöglicht, ist die Einführung von zugehörigen Typen, die in jeder Implementierung als type Output = Bit zeigt nach oben . Eine weitere bemerkenswerte Änderung besteht darin, dass die Eigenschaften des Operators nun Argumente nach Wert annehmen und sie verbrauchen, also ging ich voran und implementierte Copy für die Struktur.

Verwandte Themen