Iterating trait then calling functions without &self

So i have this object trait

trait Object {
    fn update(world: &mut World, index: usize) where Self: Sized;
}

And in that is an update function.
Now originally the update function looked like this

fn update(&mut self world: &mut World);

Next i had the world struct

struct World {
    objects: Vec<Box<dyn Object>>
}

And in that world struct there was a different update function that was supposed to update all the objects in the world. My original implementation of Object::update could not work because

  1. I had to split the borrow meaning hat i had to copy the object, which breaks rusts vtable rules
  2. There were 2 mutable borrows

So i changed it so there was one mutable borrow which was the world, and to get the object i had to use the index parameter.

impl World {
    fn update(&mut self) {
        for index in 0..self.objects.len() {
            self.objects[index].update(self, index)
        }
    }
}

fn main() {}

But there was another problem, and that is what i want to fix

error[E0599]: no method named update found for struct Box<(dyn Object + 'static)> in the current scope
--> src/main.rs:12:33
|
12 | self.objects[index].update(self, index)
| ^^^^^^ this is an associated function, not a method
|
= note: found the following associated functions; to be used as methods, functions must have a self parameter
note: the candidate is defined in the trait Object

Now the compiler did give me a help message

help: disambiguate the associated function for the candidate
|
12 | <Box<(dyn Object + 'static)> as Object>::update(self.objects[index], self, index)
|
using it as a guide i came up with this code

<Box<(dyn Object + 'static)> as Object>::update(self, index)

However the compiler complained again saying that

the trait Object is not implemented for Box<(dyn Object + 'static)>
unboxing and using lifetimes gives a similar error

So, how can i fix this?

Tip on formatting: Error messages belong in code blocks, not in quotations.


Something like this might work for you:

trait Object {
    fn update(&self) -> fn(world: &mut World, index: usize);
}

struct World {
    objects: Vec<Box<dyn Object>>
}

impl World {
    fn update(&mut self) {
        for index in 0..self.objects.len() {
            self.objects[index].update()(self, index)
        }
    }
}

struct MyObject;
impl Object for MyObject {
    fn update(&self) -> fn(world: &mut World, index: usize) {
        |world, index| {
            // can' use `self` here, but that's deliberate
            println!("called update with index {index}");
        }
    }
}

Or, if you don’t like the need to explicitly do that |world, index| { … } business in the implementation, you can do something like this:

trait Object: ObjectDyn {
    fn update(world: &mut World, index: usize)
    where
        Self: Sized;
}

trait ObjectDyn {
    fn update_fn(&self) -> fn(world: &mut World, index: usize);
}

impl<T: Object> ObjectDyn for T {
    fn update_fn(&self) -> fn(world: &mut World, index: usize) {
        T::update
    }
}

struct World {
    objects: Vec<Box<dyn Object>>,
}

impl World {
    fn update(&mut self) {
        for index in 0..self.objects.len() {
            self.objects[index].update_fn()(self, index)
        }
    }
}

struct MyObject;
impl Object for MyObject {
    fn update(world: &mut World, index: usize) {
        println!("called update with index {index}");
    }
}

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.