2016-09-12 1 views
0

я объявил массив пользовательского признака Animal для того, чтобы экспериментировать с полиморфизмом в Русте, но компилятор, кажется, делает вывод типа на подтипа первого элемента вместо:Почему я не могу использовать вывод типа с объявлением массива?

fn main() { 
    let animals = [Cat, Dog, Cat, Lion, Dog, Lion]; 
    for single_animal in animals { 
     single_animal.talk(); 
    } 
} 

trait Animal { 
    fn talk(&self); 
} 

struct Cat; 
struct Dog; 
struct Lion; 

impl Animal for Cat { 
    fn talk(&self) { 
     println!("Je miaule !"); 
    } 
} 

impl Animal for Dog { 
    fn talk(&self) { 
     println!("J'aboie !"); 
    } 
} 

impl Animal for Lion { 
    fn talk(&self) { 
     println!("Je rugit !"); 
    } 
} 

Компилятор жалуется на то, что первый элемент является Cat, а не другие:

error: mismatched types [--explain E0308] 
--> src/main.rs:3:25 
    |> 
3 |>  let animals = [Cat, Dog, Cat, Lion, Dog, Lion]; 
    |>       ^^^ expected struct `Cat`, found struct `Dog` 
note: expected type `Cat` 
note: found type `Dog` 

error: mismatched types [--explain E0308] 
--> src/main.rs:3:35 
    |> 
3 |>  let animals = [Cat, Dog, Cat, Lion, Dog, Lion]; 
    |>         ^^^^ expected struct `Cat`, found struct `Lion` 
note: expected type `Cat` 
note: found type `Lion` 

error: mismatched types [--explain E0308] 
--> src/main.rs:3:41 
    |> 
3 |>  let animals = [Cat, Dog, Cat, Lion, Dog, Lion]; 
    |>           ^^^ expected struct `Cat`, found struct `Dog` 
note: expected type `Cat` 
note: found type `Dog` 

error: mismatched types [--explain E0308] 
--> src/main.rs:3:46 
    |> 
3 |>  let animals = [Cat, Dog, Cat, Lion, Dog, Lion]; 
    |>            ^^^^ expected struct `Cat`, found struct `Lion` 
note: expected type `Cat` 
note: found type `Lion` 

error: the trait bound `[Cat; 6]: std::iter::Iterator` is not satisfied [--explain E0277] 
--> src/main.rs:4:5 
    |> 
4 |>  for single_animal in animals { 
    |> ^
note: `[Cat; 6]` is not an iterator; maybe try calling `.iter()` or a similar method 
note: required by `std::iter::IntoIterator::into_iter` 

Добавление Animal типа в массив не решает проблему либо. Поскольку на этот раз я получаю больше ошибок:

error: mismatched types [--explain E0308] 
--> src/main.rs:3:27 
    |> 
3 |>  let animals: Animal = [Cat, Dog, Cat, Lion, Dog, Lion]; 
    |>       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait Animal, found array of 6 elements 
note: expected type `Animal` 
note: found type `[Cat; 6]` 

error: the trait bound `Animal: std::marker::Sized` is not satisfied [--explain E0277] 
--> src/main.rs:3:9 
    |> 
3 |>  let animals: Animal = [Cat, Dog, Cat, Lion, Dog, Lion]; 
    |>   ^^^^^^^ 
note: `Animal` does not have a constant size known at compile-time 
note: all local variables must have a statically known size 

error: the trait bound `Animal: std::marker::Sized` is not satisfied [--explain E0277] 
--> src/main.rs:4:5 
    |> 
4 |>  for single_animal in animals { 
    |> ^
note: `Animal` does not have a constant size known at compile-time 
note: required by `std::iter::IntoIterator::into_iter` 

error: the trait bound `Animal: std::iter::Iterator` is not satisfied [--explain E0277] 
--> src/main.rs:4:5 
    |> 
4 |>  for single_animal in animals { 
    |> ^
note: `Animal` is not an iterator; maybe try calling `.iter()` or a similar method 
note: required by `std::iter::IntoIterator::into_iter` 
+0

Потенциальный дубликат http://stackoverflow.com/q/27957103/155423; http://stackoverflow.com/q/25818082/155423; http://stackoverflow.com/q/36357995/155423. – Shepmaster

+0

Я не полностью согласен с дублированием, так как вектор является динамическим использованием, а объявление массива в одной строке показывает особенности и сложности, которые являются специфическими для массива. – loloof64

+0

Нет, ни один из ответов не относится к массиву, отличному от буквенного синтаксиса. '[& Cat as & Animal, & Dog]' и 'vec! [& Cat as & Animal, & Dog]' работают так же, как и 'let animals: [& Animal, 2] = [& Cat, & Dog]' и 'let animals: Vec <&Animal> = vec! [& Cat, & Dog] '. Кроме того, ваш вопрос [не показал никаких усилий] (http://meta.stackoverflow.com/q/261592/155423) в поисках похожих вопросов или потенциального беспокойства о том, что массив отличается от вектора. – Shepmaster

ответ

7

Ржавые массивы однородны, что означает, что каждый элемент в нем имеет тот же тип. Таким образом, вы не можете иметь массив с Dog и Cat. Но у вас может быть массив, полный так называемых «объектов-признаков», в вашем случае &Animal. Вот как мы явно запрашиваем полиморфизм во время выполнения.

Вы должны явно сообщить компилятору, что хотите получить массив с объектами признаков. Компилятор выводит тип массива на основе первого элемента в инициализаторе, так что давайте явно бросить эту вещь:

let animals = [&Cat as &Animal, &Dog, &Cat, &Lion, &Dog, &Lion]; 

Обратите внимание, что мы также добавили & ко всем значениям, потому что вы можете работать только с указателями объекты признаков. (после этого появляется другая небольшая ошибка в вашем коде, но решение довольно простое). See on the playground.

+1

Спасибо.Поэтому я забыл использовать Type Objects (ссылки), чтобы перенести первый элемент в объект типа Animal и получить итератор от животных. Большое спасибо. Мой путь к обучению Rust растет. – loloof64

+2

@ loloof64 Просто быть педантичным по терминологии: «объекты-объекты», а не «объекты типа». (Все объекты _must_ имеют тип, поэтому избыточно говорить конкретно о «объектах типа». С другой стороны, черты не являются типами _concrete_, поэтому «объект-объект» имеет значение «объект типа который реализует определенную черту », что является хорошим способом поговорить об этом). – Kroltan

+1

@ Kroltan. Как вы сказали, это, безусловно, хороший способ для начинающих подумать обо всем этом. Но на самом деле (будучи педантичным: P) черта является конкретным типом. Вы можете написать 'impl MyTrait {}' и использовать имя признака в каждой ситуации, где вы могли бы использовать, скажем, имя структуры. Единственная проблема заключается в том, что типы признаков являются нестандартными (не 'impl Sized'), что делает их незаконными во многих ситуациях. Удовлетворительный факт: вот почему новый «implit trait» -RFC предлагает синтаксис «impl Trait» вместо «Trait», потому что последний синтаксис уже действителен. –

3

Это потому, что Cat, и Lion все разные типы, и вы можете иметь только один массив.

Вы можете использовать свойство объектов, как Лукас предложил, но то, что вы после этого можно было бы достичь гораздо легче (объекты Trait не то, что я бы рекомендовал начинающему Rust), с общим Animal перечисления:

use self::Animal::*; 

fn main() { 
    let animals = [Cat, Dog, Cat, Lion, Dog, Lion]; 
    for single_animal in animals.iter() { 
     single_animal.talk(); 
    } 
} 

trait AnimalSkills { 
    fn talk(&self); 
} 

enum Animal { 
    Cat, 
    Dog, 
    Lion 
} 

impl AnimalSkills for Animal { 
    fn talk(&self) { 
     match *self { 
      Cat => println!("Je miaule !"), 
      Dog => println!("J'aboie !"), 
      Lion => println!("Je rugit !") 
     } 
    } 
} 

Также обратите внимание, что вам необходимо позвонить .iter(), чтобы иметь возможность выполнять итерацию по массиву.

+0

Спасибо. Не волнуйтесь о характеристиках объекта trait, я уже использовал Java-интерфейсы, которые кажутся похожими. И реализовать их мне не так сложно. – loloof64

+2

@ loloof64 Не обязательно, чтобы реализовать их * hard *; это вопрос того, что является лучшим инструментом для работы. Вы должны подумать о том, предлагает ли Rust лучшее решение перед тем, как автоматически достичь решения, которое вам удобно в Java. – trentcl

+0

Да, ты прав. В моем случае я не делаю так много настроек/определения в животных impl. Так что в этом случае это очень много для стольких. – loloof64