使用 Any 特性获取对包含引用的结构的引用时的生命周期问题

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

我运行用一个小游戏解决了一辈子的问题。下面的代码代表了更新循环的一个非常简化的版本。 我需要容器可变引用来获取对其他游戏对象的引用或创建新对象或触发功能。

出于这个原因,我需要 Any 特征才能将特征转换为结构,所以在我的 GameObj 特征中我添加了一个 as_any 方法,但是这个导致终身问题。

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

当我尝试构建代码时,出现以下错误消息。 如果我在 update 函数中注释 out/delete let any = val.as_any(); 它编译正常。

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();
   |                       ^^^^^^

如何在不使用 'static 的情况下完成这项工作,或者为什么这是不可能的?

Anydeclared trait Any: 'static and can only store 'static types。因此,为了使 dyn Any + 'a 成为格式正确的类型,您的 as_any 方法被赋予隐式 'a: 'static 绑定,导致您显示的生命周期错误。

如果没有这个限制,你可以通过将 'a 类型放入 Any 并输出 'static 类型来破坏安全性,因为 TypeId 无法区分——生命周期在编译过程中被删除。有关详细信息,请参阅 discussion on RFC 1849

你应该更仔细地考虑一下为什么要使用Any。这几乎从来都不是你真正想要的。也许像您可能想要存储的所有不同对象类型的 enum 类型这样简单的东西会更好地满足您的用例?

如果你真的想使用 Any,那么你需要想办法让你的类型 'staticRc (or Arc,如果涉及线程)通常有助于此目的;例如,您可以让 object 存储 Rc<String>(或更好,Rc<str>)而不是 &'a String.