Can`t get my type to be working with Vec

#1

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

0 Likes

#2

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

#3

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?

0 Likes

#4

Try

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

#5

Works perfectly.

Thanks!

0 Likes

#6

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

#7

I prefer this

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