1

I'm trying to create a VecDeque of structs that all implement an Animal trait. This code works, but I don't understand why adding ' static fixes it and how to make it use 'a instead.

pub trait Animal {
    fn says(self) -> Option<String>;
}

use std::collections::VecDeque;

pub struct Zoo {
    list: VecDeque<Box<dyn Animal>>,
}

impl Zoo {
    pub fn new() -> Zoo {
        Zoo {
            list: VecDeque::new(),
        }
    }

    pub fn add<T>(&mut self, animal: T)
    where
        T: Animal + 'static,
    {
        self.list.push_back(Box::new(animal));
    }
}

Two questions:

  1. Could someone please explain how to use 'a properly and how this would work / what it would mean? And also I guess why I even need a lifetime here (is it because I'm using Box)?
  2. I'm also confused why I have to use #[path="..."] since without it, it asks me to move the file to src/lib/animal.rs but when I move it, that still doesn't work.
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
John
  • 15
  • 5
  • 2
    https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ec3cab8a120010af0b52dffb30c10f28, but I don't know if it's make sense to do that – Stargateur Oct 21 '19 at 01:07
  • @Stargateur That's awesome, you fixed it and I can compile now :) Thank you so much for taking the time! Is there some basic logic as to how that works and why it's better than static? Also you say you don't know if it makes sense to do that, is it not the best route to go or there's some other reason? – John Oct 21 '19 at 03:40
  • @John `Box` is equal to `Box` in this context. So, anything you put in `VecDeque` has to be `'static` - that's why you add `'static` bound in `add` method's `where` clause. `'static` limits what you can put into `Zoo`, only objects without references (or with `'static` references) in them are `'static` themselves. – L117 Oct 21 '19 at 05:32
  • @John And what about `#[path="..."]`, you're violating convention about project structure. Here's documentation for this: https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html – L117 Oct 21 '19 at 05:40
  • Thank you for following up @L117. Following https://doc.rust-lang.org/book/ch07-05-separating-modules-into-different-files.html I still can't get it to work. It asks me to create a file in `src/lib/front_of_house.rs` and not in `src/front_of_house.rs` as the guide suggests. I'm using 2018 edition and can't figure out what I'm doing wrong. – John Oct 21 '19 at 14:33
  • @L117 Ok, I think somehow I got it to work. My `src/lib.rs` has `pub mod zoo;`. My `src/zoo.rs` has `pub mod animal; pub mod monkey;`. My `src/zoo/monkey.rs` has `use crate::zoo::animal::Animal`. Is this structure normal? – John Oct 21 '19 at 15:15
  • @John No. `crate` references either `src/lib.rs` or `src/main.rs`. For some module `crate::zoo` you should either have no separate file (Module has body in `lib.rs`/`main.rs`), `src/zoo.rs` file (If there are no nested *module files*) or `src/zoo/mod.rs` file (If there *are* nested *module files*). Next, for `crate::zoo::monkey` module you should either have no file (Module has body in either `src/zoo.rs` or in `src/zoo/mod.rs`), have `src/zoo/monkey.rs` file or `src/zoo/monkey/mod.rs` file. – L117 Oct 22 '19 at 07:39

1 Answers1

2

As already pointed out, Box<dyn Animal> is equivalent to Box<dyn Animal + 'static>, which means a pointer to something which is valid through the whole program (like string literals). This is probably not what you want.

You want it such that your Zoo cannot live longer than your Animals. (This is what the compiler will enforce). So you annotate Zoo with a lifetime 'a and you require that every Animal which is stored in the Zoo lives at least as long as 'a:

pub struct Zoo<'a> {
    animals: VecDeque<Box<dyn Animal + 'a>>,
}   

The compiler will check whether your lifetime annotations will make sense and enforce that a reference cannot outlive an object.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Unlikus
  • 1,419
  • 10
  • 24