使用Any特质获取包含引用的结构的引用时的生命周期问题 [英] Lifetime issue when using the Any trait to get references to structs containing references

查看:56
本文介绍了使用Any特质获取包含引用的结构的引用时的生命周期问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在玩小游戏时遇到了一生的问题.下面的代码表示更新循环的简化版本.我需要容器可变引用来获取对其他游戏对象的引用,或者创建新的对象或触发功能.

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.

由于这个原因,我需要 Any 特性才能将其转换为结构,因此在我的 GameObj 特性中添加了 as_any 方法,但这会导致生命周期问题.

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);
            }
        }
    }
}

游乐场

当我尝试构建代码时,它导致以下错误消息.如果我在 update 函数中注释/删除 let any = val.as_any(); ,则可以正常编译.

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

如何在不使用'static 的情况下实现此目的,或者为什么这不可能呢?

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

推荐答案

任何,并且可以仅存储 'static 类型.因此,为了使 dyn Any +'a 成为格式正确的类型,您的 as_any 方法被赋予了隐式的'a:'static 绑定,导致您显示的生命周期错误.

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.

如果没有此限制,则可以通过将'a 类型放入 Any 类型并获取'static 类型,因为 TypeId 不能说出区别-编译期间会删除生命.有关更多信息,请参见关于RFC 1849的讨论.

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.

您应该更仔细地考虑为什么要使用 Any .这几乎从来不是您真正想要的.也许和 枚举 一样简单a>您可能要存储的所有不同对象类型的类型将更好地满足您的用例?

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?

如果您真的想使用 Any ,那么您将需要一种使类型变为'static 的方法. Rc (或 Arc (如果涉及线程)通常对此很有帮助;例如,您可以让 object 存储 Rc< String> (或者更好的是 Rc< str> ),而不是&'一个字符串.

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.

这篇关于使用Any特质获取包含引用的结构的引用时的生命周期问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆