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

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

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?
  • Пакет ржавчины с библиотекой и двоичным?
  • Как преобразовать строку C в строку Rust и вернуться через FFI?
  • Как преобразовать String в & 'static str
  • Каков правильный способ вернуть Итератор (или любой другой признак)?
  • Как вызвать метод, когда свойство и структура используют одно и то же имя?
  • Передача изменчивой самостоятельной ссылки на метод принадлежащего ему объекта
  • Как передать ссылку на переменную стека в stream?
  • Условно перебрать один из нескольких возможных iteratorов
  • Печатает! заимствовать или владеть переменной?
  • Давайте будем гением компьютера.