2015-10-17 5 views
7

Ein einfaches Programm, um dieses Verhalten zu zeigen:Warum steht die Trait-Implementierung für Box <T> in Konflikt mit Fn()?

use std::boxed::Box; 

struct Cow; 

trait CanSpeak { 
    fn speak(&self); 
} 

impl CanSpeak for Cow { 
    fn speak(&self) { 
     println!("moo"); 
    } 
} 

impl<F: Fn()> CanSpeak for F { 
    fn speak(&self) { 
     self(); 
    } 
} 

impl<T: CanSpeak> CanSpeak for Box<T> { 
    fn speak(&self) { 
     (**self).speak() 
    } 
} 

fn lol_speak() { 
    println!("lol") 
} 

fn lets_speak<T: CanSpeak>(t: & T) { 
    t.speak(); 
} 

fn main() { 
    let cow = Cow; 
    lets_speak(&cow); 

    lets_speak(&lol_speak); 

    let boxed_cow = Box::new(Cow); 
    lets_speak(&boxed_cow); 
} 

Compilation nicht mit:

test.rs:15:1: 19:2 error: conflicting implementations for trait `CanSpeak` [E0119] 
test.rs:15 impl<F: Fn()> CanSpeak for F { 
test.rs:16  fn speak(&self) { 
test.rs:17   self(); 
test.rs:18  } 
test.rs:19 } 
test.rs:15:1: 19:2 help: run `rustc --explain E0119` to see a detailed explanation 
test.rs:21:1: 25:2 note: note conflicting implementation here 
test.rs:21 impl<T: CanSpeak> CanSpeak for Box<T> { 
test.rs:22  fn speak(&self) { 
test.rs:23   (**self).speak() 
test.rs:24  } 
test.rs:25 } 
error: aborting due to previous error 

Meine Fragen sind:

  1. As far as I can tellBox<T> nicht implementiert Fn() Merkmal. Warum schlägt das obige Beispiel fehl?
  2. Was ist die korrekte Implementierung für das, was ich versuche zu tun?

Ich habe gerade angefangen zu lernen Rust. Danke für Ihre Hilfe.

Antwort

6

Die beiden Konflikt tun, weil es möglich ist, für einen Typ Box<T>T Umsetzung CanSpeak und Box<T> Umsetzung Fn() zu haben. Rust Kohärenz Regeln sind nicht darüber, was ist aber was kann sein.

Hier ist ein Beispiel von Fn() für Box<Cow> Umsetzung, die Dinge klar explodieren würde, wenn es Ihr zwei generisches Merkmal Implementierungen erlaubt:

// (This attribute on the crate.) 
#![feature(unboxed_closures, core)] 

impl Fn<()> for Box<Cow> { 
    extern "rust-call" fn call(&self, _:()) { } 
} 

impl FnMut<()> for Box<Cow> { 
    extern "rust-call" fn call_mut(&mut self, _:()) { } 
} 

impl FnOnce<()> for Box<Cow> { 
    type Output =(); 
    extern "rust-call" fn call_once(self, _:()) { } 
} 
für Ihre Antwort
+2

Dank Chris, aber ich fürchte, ich es immer noch nicht bekommen . Kannst du erklären, was "Box" in diesem Fall besonders macht, dass Rust denkt, dass es einen Konflikt geben kann? Zum Beispiel Wenn, ich verstehe Ihre Erklärung richtig, irgendein Container, sagen wir 'Arc ' sollte auch Konflikt, weil 'T' kann' CanSpeak' implementieren und 'Arc ' kann 'Fn()' implementieren. Aber "Box" in meinem Beispiel mit "Arc" zu ersetzen funktioniert gut. – Vikas

+3

Es gibt * nichts * Besonderes daran. Es gibt nur zwei generische Implementierungen für ein Merkmal, die sich überschneiden können. –

+0

Warum funktioniert 'Arc'? In meinem Beispiel, wenn ich "Box" durch "Arc" ersetze, kompiliert es ohne irgendwelche Fehler. – Vikas