2017-01-27 14 views
0

У меня есть две Структуры, Dog и Cat:понижающее приведение ржавчины Комбинации Trait

struct Dog { 
    weight: f64 
} 
struct Cat { 
    weight: f64 
} 

и две черты MakesSound и HasWeight

trait MakesSound { 
    fn make_sound(&self); 
} 

impl MakesSound for Dog { 
    fn make_sound(&self) { 
     println!("Bark bark!"); 
    } 
} 

impl MakesSound for Cat { 
    fn make_sound(&self) { 
     println!("Go away."); 
    } 
} 

trait HasWeight { 
    fn get_weight(&self) -> f64; 
} 

impl HasWeight for Dog { 
    fn get_weight(&self) -> f64 { self.weight } 
} 

impl HasWeight for Cat { 
    fn get_weight(&self) -> f64 { self.weight } 
} 

Я хотел бы иметь возможность хранить их в гетерогенной Vec и затем используйте оба их черты

trait Animal: MakesSound + HasWeight {} 
impl<T: MakesSound + HasWeight> Animal for T {} 

fn main() { 
    let dog = Dog{ weight: 45.0 }; 
    let cat = Cat{ weight: 12.0 }; 
    let animals: Vec<&Animal> = vec![&dog, &cat]; 
    for animal in animals { 
     animal.make_sound(); 
     println!("{}", animal.get_weight()); 
     //print_weight(animal as &HasWeight); 
    } 
} 

Как бы определить print_weight функции, которая имела тип

fn print_weight(x: &HasWeight); 

так, что моя функция будет требовать как мало информации, насколько это возможно, но мой Vec хранит столько информации, сколько возможно?

Я получаю ошибку от раскомментирован линии выше

error: non-scalar cast: `&Animal` as `&HasWeight` 
+1

https://stackoverflow.com/questions/28632968/why-doesnt-rust-support-trait-object-upcasting –

ответ

2

Вот print_weight функция, которая является общим над типами с HasWeight черты. К сожалению, я слишком неопытен с Rust, чтобы рассказать вам, почему необходима дополнительная привязка ?Sized.

fn print_weight<T: HasWeight + ?Sized>(thing: &T) { 
    println!("{}", thing.get_weight()); 
} 

Это может быть вызван из вашего цикла без какого-либо литья: print_weight(animal).

Playground link

+0

Это действительно работает, хотя ... Я думал, что Sized черта была требованием , что компилятор может быть заперт, сообщив, что параметр Sized является необязательным, предполагает, что компилятор может обойтись без него. Мне было бы интересно узнать, как и если статическая отправка все еще происходит. – Dave

+0

Для решения обеих ваших проблем: для отображения T в нестандартных типах требуется привязка '? Sized'. В частности, когда 'T = HasWeight', аргумент функции становится объектом-символом (' & HasWeight'), который динамически отправляется. В других случаях известен конкретный тип объекта за аргументом, который будет статически отправлен. –