2015-10-17 10 views
7

Un programma semplice per illustrare questo comportamento:Perché l'implementazione del tratto per Box <T> è in conflitto con 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); 
} 

compilazione fallisce con:

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 

Le mie domande sono:

  1. As far as I can tellBox<T> non implementa Fn() caratteristica. Allora perché sopra l'esempio fallisce?
  2. Qual è l'implementazione corretta per ciò che sto cercando di fare?

Ho appena iniziato a studiare Rust. Grazie per l'aiuto.

risposta

6

I due sono in conflitto, perché è possibile per un tipo Box<T> avere T attuazione CanSpeak e Box<T> attuazione Fn(). Le regole di coerenza della ruggine non riguardano ciò che è ma quale può essere.

Ecco un esempio di implementazione Fn() per Box<Cow>, che ovviamente esplodere le cose, se ha permesso tuoi due implementazioni tratto generici:

// (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, _:()) { } 
} 
+2

Grazie Chris per la risposta, ma ho paura che non ho ancora capito . Puoi spiegare cosa rende 'Box' speciale in questo caso che Rust pensa che possa essere in conflitto? Ad esempio, se capisco correttamente la tua spiegazione, qualsiasi contenitore, diciamo "Arc " dovrebbe anche essere in conflitto perché "T" può implementare "CanSpeak' e" Arc "può implementare" Fn() ". Ma Sostituire 'Box' nel mio esempio con' Arc' funziona perfettamente. – Vikas

+3

Non c'è * niente * speciale a riguardo. È solo che hai fornito due implementazioni generiche per un tratto che possono sovrapporsi. –

+0

Allora perché funziona 'Arc'? Nel mio esempio, se sostituisco 'Box' con' Arc' compila senza errori. – Vikas

Problemi correlati