How can I create a Vector of References to Trait Objects?

Hi,

I recently started learning Rust, and so far I'm really enjoying it. I ran across a situation today which I don't understand, and was hoping somebody with more experience could shed some light on it, since it feels like it could be coming from a fundamental gap in my understanding.

I'm trying to create a vector of references to trait objects. I can implement this like so, and it compiles without a problem:

trait Foo {}

struct Bar {}

impl Foo for Bar {}

fn main() {
    let bars = vec![Bar {}];

    let mut foos: Vec<&dyn Foo> = vec![];
    for bar in bars.iter() {
        foos.push(bar);
    }
}
   Compiling playground v0.0.1 (/playground)
    Finished dev [unoptimized + debuginfo] target(s) in 0.61s
     Running `target/debug/playground`

However, when I try to create it directly using the collect() function, it does not compile:

trait Foo {}

struct Bar {}

impl Foo for Bar {}

fn main() {
    let bars = vec![Bar {}];

    let foos: Vec<&dyn Foo> = bars.iter().collect();
}
   Compiling playground v0.0.1 (/playground)
error[E0277]: a value of type `Vec<&dyn Foo>` cannot be built from an iterator over elements of type `&Bar`
  --> src/main.rs:10:43
   |
10 |     let foos: Vec<&dyn Foo> = bars.iter().collect();
   |                                           ^^^^^^^ value of type `Vec<&dyn Foo>` cannot be built from `std::iter::Iterator<Item=&Bar>`
   |
   = help: the trait `FromIterator<&Bar>` is not implemented for `Vec<&dyn Foo>`
   = help: the trait `FromIterator<T>` is implemented for `Vec<T>`
note: the method call chain might not have had the expected associated types
  --> src/main.rs:10:36
   |
8  |     let bars = vec![Bar {}];
   |                ------------ this expression has type `Vec<Bar>`
9  |
10 |     let foos: Vec<&dyn Foo> = bars.iter().collect();
   |                                    ^^^^^^ `Iterator::Item` is `&Bar` here
note: required by a bound in `collect`
  --> /rustc/84c898d65adf2f39a5a98507f1fe0ce10a2b8dbc/library/core/src/iter/traits/iterator.rs:1887:5

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` due to previous error

Could somebody please explain why a value of type Vec<&dyn Foo> cannot be built from Iterator<Item=&Bar>? I'm not sure if I'm missing something small, or fundamentally misunderstanding iterators and/or dynamic dispatch.

Thank you!

You misunderstand references, I'm 99% sure. Common mistake for newcomers from tracing GC-based languages is to assume that reference is something that points to heap-allocated object, GC-controlled object.

But in Rust (like in C++) references are temporary objects which are used to access objects owned by someone else.

Array of references is technically not invalid data structure but very rarely useful one.

Why? What's the end goal? Most likely you want Box or maybe Rc<RefCell> or Arc<Mutex>, not reference.

Because &Bar and &dyn Foo are different types. Sure, one can be converted into the other, but they are still different types. You'll need to insert a conversion step. For example:

let foos: Vec<&dyn Foo> = bars.iter().map(|b| b as &dyn Foo).collect();

The reason it works with the for loop is because the compiler inserts the conversion automatically for you. However, this only happens in very limited circumstances.

3 Likes

Thank you @khimru and @alice!

I was using this structure as a debug step, and I plan on ultimately using Rc<RefCell> in its place, as you suggested. I see now that an array of references is not very useful :slight_smile:. Still, I was surprised that the collection didn't work, and wanted to find out why.

This makes a lot of sense! It's great that the compiler can take care of this automatically, but I'm always happy to learn more about what it's doing behind the scenes. I have only used as for primitive conversion so far, so also happy to see it used in another way.

Thank you both!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.