Can`t get my type to be working with Vec

Hello guys!
The problem is as follows:

I got a trait:

pub trait Fragment{
    //some functions that are not worth mentioning?
}

Then I have got two structs that I want to impl above trait.

pub struct Spritesheet<'a> {
    pub texture: &'a sdl2::render::Texture<'a>,
    //other fields not worth also in my opinion
}

pub struct Doodad<'a> {
    pub texture: &'a sdl2::render::Texture<'a>,
    //other fields not worth also in my opinion
}

Ofc Both impl trait:

impl Fragment for Spritesheet<'_> {
   //fn implementations
}

impl Fragment for Doodad<'_> {
   //fn implementations
}

Problem is that I need to put them into a Vector and make it mutable.

let mut test: Vec<&Fragment> = Vec::new();

let test_ss = Spritesheet::new(&texture, 400, 20, 6);

test.push(&test_ss);

But got

|                                                                                                                                 
163 |     test.push(&test_ss);                                                                                                        
|                ^^^^^^^ borrowed value does not live long enough                                                                 
...                                                                                                                                   
311 | }                                                                                                                               
| - `test_ss` dropped here while still borrowed                                                                                   
|                                                                                                                                 
= note: values in a scope are dropped in the opposite order they are created                                         

Line 311 is enclosing bracket of fn main()

Tried adding β€œ<'a>” to trait istelf and then along with impls blocks, but the error is the same then.

Made it work with Box::new()

//This works like a charm
let mut fragments: Vec<Box<Fragment>> = Vec::new();

fragments.push(Box::new(Spritesheet::new(&texture, 400, 20, 6)));
fragments.push(Box::new(Doodad::new(&texture2, 100, 100, 6)));
fragments.push(Box::new(Doodad::new(&texture3, 100, 100, 6)));

But the Box version is making it`s content immutable.

It seems an easy error, but I can not find the correct answer.
Cheers!
Wowo

The Box is necessary because of trait objects (Which are now defined as dyn Trait instead of Trait) are unsized, and therefore can’t fit into Vec which requires T to be sized. As for immutability of the Box's contents, Box implements DerefMut, meaning that if you want to mutate it you can:

  1. Call a &mut self function
  2. Directly call boxed.deref_mut() to get a mutable reference to the value stored in the box
2 Likes

I love this community. <3 Answer in less than 10 min.
You are right, I can just use it in loop:

for i in 0..fragments.len() {
            fragments[i].mut_self_fn();
}

But I cannot use it like that:

for x in &fragments{
            x.mut_self_fn();
}

Because of:

    |                                                                                                                                 
245 |                 x.mut_self_fn();                                                                                                 
    |                 ^ cannot borrow as mutable **

Is there maybe better approach?

Try

for i in collection.iter_mut() {
    //
}
1 Like

Works perfectly.

Thanks!

It is best practice to mark trait objects with the dyn keyword.
I.e.
dyn Fragment
Box<dyn Fragment>

This is to signal that dynamic dispatch is being used.

1 Like

I prefer this

for x in &mut fragments {
    x.mut_self_fn();
}
3 Likes