Вектор объектов, принадлежащих признаку

Рассмотрим следующий код:

trait Animal { fn make_sound(&self) -> String; } struct Cat; impl Animal for Cat { fn make_sound(&self) -> String { "meow".to_string() } } struct Dog; impl Animal for Dog { fn make_sound(&self) -> String { "woof".to_string() } } fn main () { let dog: Dog = Dog; let cat: Cat = Cat; let v: Vec = Vec::new(); v.push(cat); v.push(dog); for animal in v.iter() { println!("{}", animal.make_sound()); } } 

Компилятор говорит мне, что v является вектором Animal когда я пытаюсь нажать cat (несоответствие типа)

Итак, как я могу сделать вектор объектов, принадлежащих к признаку, и называет соответствующий метод признаков для каждого элемента?

Vec не является законным, но компилятор не может вам сказать, потому что несоответствие типа каким-то образом скрывает его. Если мы удалим вызовы для push , компилятор даст нам следующую ошибку:

 :22:9: 22:40 error: instantiating a type parameter with an incompatible type `Animal`, which does not fulfill `Sized` [E0144] :22 let mut v: Vec = Vec::new(); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

Причина, почему это не является законным, заключается в том, что Vec хранит много объектов T последовательно в памяти. Тем не менее, Animal – это черта, и черты не имеют размера (у Cat и Dog не гарантируется одинаковый размер).

Чтобы решить эту проблему, нам нужно сохранить что-то, что имеет размер в Vec . Наиболее простым решением является обертывание значений в Box , то есть Vec> . Box имеет фиксированный размер («указатель жира», если T – это признак, простой указатель в противном случае).

Вот main :

 fn main () { let dog: Dog = Dog; let cat: Cat = Cat; let mut v: Vec> = Vec::new(); v.push(Box::new(cat)); v.push(Box::new(dog)); for animal in v.iter() { println!("{}", animal.make_sound()); } } 

Вы можете использовать объект ссылочного объекта &Animal для заимствования элементов и сохранения этих объектов-признаков в Vec . Затем вы можете перечислить его и использовать интерфейс признака.

Изменение универсального типа Vec путем добавления символа & перед признаком будет работать:

 fn main() { let dog: Dog = Dog; let cat: Cat = Cat; let mut v: Vec<&Animal> = Vec::new(); // ~~~~~~~ v.push(&dog); v.push(&cat); for animal in v.iter() { println!("{}", animal.make_sound()); } // Ownership is still bound to the original variable. println!("{}", cat.make_sound()); } 

Это здорово, если вы захотите, чтобы исходная переменная сохраняла право собственности и повторно использовала ее позже.

Имейте в виду, что сценарий выше, вы не можете передавать права собственности на dog или cat потому что Vec заимствовал эти конкретные экземпляры в том же объеме.

Введение новой области может помочь справиться с этой конкретной ситуацией:

 fn main() { let dog: Dog = Dog; let cat: Cat = Cat; { let mut v: Vec<&Animal> = Vec::new(); v.push(&dog); v.push(&cat); for animal in v.iter() { println!("{}", animal.make_sound()); } } let pete_dog: Dog = dog; println!("{}", pete_dog.make_sound()); } 
  • Как остановить итерацию и вернуть ошибку, когда Iterator :: map возвращает результат: Err?
  • Println! error: ожидается, что аргумент literal / format должен быть строковым литералом
  • Есть ли способ объединить несколько признаков, чтобы определить новый признак?
  • Как синтаксис отличается от регулярной привязки к жизни?
  • В чем разница между iter и in_iter?
  • Можно ли управлять размером массива с помощью параметра типа общего?
  • Автоматически реализовать черты замкнутого типа для новых типов Rust (кортежи с одним полем)
  • Не может заимствовать как неизменяемый, поскольку он также заимствован как изменяемый в аргументах функции
  • Как передать непересекающиеся fragmentы из вектора в разные streamи?
  • Как преобразовать 'struct' в '& '?
  • Зачем пытаться! () И? не компилироваться при использовании в функции, которая не возвращает результат?
  • Interesting Posts

    разница между броском и броском нового исключения ()

    JButton () работает только при наведении мыши

    Ошибка получения родительского элемента для элемента: ресурс не найден, который соответствует указанному имени после обновления до AppCompat v23

    Мелкозернистая конфигурация sudoers (допустимые аргументы командной строки)

    Как связать XML с XSD с помощью schemaLocation или noNamespaceSchemaLocation?

    Регулятор громкости в приложении android

    Проверьте, существует ли файл на удаленном сервере, используя его URL

    Итерирование по основному циклу «для» с использованием Handlebars.js

    проверьте, есть ли функция «это число» в Oracle

    Отметка checkbox в pdf с помощью itextsharp

    Есть ли способ изменить цвет точек индикатора страницы

    андроид на прослушивателе изменения текста

    Чтение файла sqlite из папки с данными

    Приостановить / возобновить процесс простым способом?

    Неужели System.nanoTime () полностью бесполезен?

    Давайте будем гением компьютера.