Lifetime issue when using the Any trait to get references to structs containing references

谁都会走 提交于 2020-12-26 04:28:26

问题


I ran into a lifetime problem with a little game. The below code represents a very boiled down version of the update loop. I need the container mutable reference to get references to other game objects or to create new ones or trigger a functionality.

For that reason, I need the Any trait to be able to cast the trait to a struct, so in my GameObj trait I added an as_any method, but this resulted in a lifetime issue.

use std::any::Any;

trait GameObj<'a> {
    fn as_any<'b>(&'b self) -> &'b (dyn Any + 'a);
    fn update(&mut self, cont: &mut container);
}

struct object<'a> {
    content: &'a String,
}

impl<'a> GameObj<'a> for object<'a> {
    fn as_any<'b>(&'b self) -> &'b (dyn Any + 'a) {
        return self;
    }

    fn update(&mut self, cont: &mut container) {
        let val = cont.get_obj().unwrap();
        let any = val.as_any();
    }
}

struct container<'a> {
    data: Vec<Box<dyn GameObj<'a> + 'a>>,
}
impl<'a> container<'a> {
    fn get_obj<'b>(&'b self) -> Option<&'b Box<dyn GameObj<'a> + 'a>> {
        return Some(&self.data[0]);
    }
}

pub fn main() {
    let a = String::from("hallo");
    let b = String::from("asdf");
    {
        let abc = object { content: &a };
        let def = object { content: &b };
        let mut cont = container { data: Vec::new() };
        cont.data.push(Box::new(abc));
        cont.data.push(Box::new(def));

        loop {
            for i in 0..cont.data.len() {
                let mut obj = cont.data.remove(0);
                obj.update(&mut cont);
                cont.data.insert(i, obj);
            }
        }
    }
}

playground

When I try to build the code, it results in the following error message. If I comment out/delete let any = val.as_any(); in the update function it compiles fine.

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
  --> src/main.rs:18:24
   |
18 |         let val = cont.get_obj().unwrap();
   |                        ^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #3 defined on the method body at 17:5...
  --> src/main.rs:17:5
   |
17 | /     fn update(&mut self, cont: &mut container) {
18 | |         let val = cont.get_obj().unwrap();
19 | |         let any = val.as_any();
20 | |     }
   | |_____^
   = note: ...so that the types are compatible:
           expected &container<'_>
              found &container<'_>
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the declared lifetime parameter bounds are satisfied
  --> src/main.rs:19:23
   |
19 |         let any = val.as_any();
   |                       ^^^^^^

How I can make this work without using 'static, or why is this impossible?


回答1:


Any is declared trait Any: 'static and can only store 'static types. So in order to make dyn Any + 'a a well-formed type, your as_any method was given an implicit 'a: 'static bound, leading to the lifetime error you showed.

If not for this restriction, you would be able to break safety by putting in an 'a type into an Any and getting out a 'static type, because TypeId can’t tell the difference—lifetimes are erased during compilation. See the discussion on RFC 1849 for more information.

You should think more carefully about why you want to use Any. It’s almost never what you actually want. Perhaps something as simple as an enum type of all the different object types you might want to store would satisfy your use case better?

If you really want to use Any, then you’ll need to find a way to make your types 'static. Rc (or Arc, if threads are involved) is often helpful for this purpose; for example, you could have your object store Rc<String> (or better, Rc<str>) instead of &'a String.



来源:https://stackoverflow.com/questions/54503120/lifetime-issue-when-using-the-any-trait-to-get-references-to-structs-containing

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!