Почему я не могу использовать вывод типа с объявлением массива?
Я объявил массив пользовательских черт Animal
чтобы поэкспериментировать с полиморфизмом в Rust, но компилятор, кажется, вместо этого делает вывод типа для подтипа первого элемента:
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`
2 ответа
Массивы ржавчины являются однородными, что означает, что каждый элемент в нем имеет один и тот же тип. Таким образом, вы не можете иметь массив с Dog
с и Cat
s. Но вы можете иметь массив, полный так называемых "объектов-черт", в вашем случае &Animal
, Вот как мы явно запрашиваем полиморфизм во время выполнения.
Вы должны явно указать компилятору, что вам нужен массив, полный объектов признаков. Компилятор определяет тип массива на основе первого элемента в инициализаторе, поэтому давайте явно приведем эту вещь:
let animals = [&Cat as &Animal, &Dog, &Cat, &Lion, &Dog, &Lion];
Обратите внимание, что мы также добавили &
ко всем значениям, потому что вы можете работать только с указателями для черт объектов. (впоследствии сообщается о другой маленькой ошибке в вашем коде, но решение довольно простое). Смотрите на детской площадке.
Это потому что Cat
, Dog
а также Lion
все разные типы, и вы можете иметь только один в массиве.
Вы могли бы использовать объекты черт, как предложил Лукас, но то, что вам нужно, могло быть достигнуто гораздо проще (объекты черт - это не то, что я бы порекомендовал начинающему 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()
для того, чтобы иметь возможность перебирать массив.