Rust 使用Any trait获取对包含引用的结构的引用时的生存期问题
我在一个小游戏中遇到了一生的问题。下面的代码表示更新循环的简化版本。 我需要容器可变引用来获取对其他游戏对象的引用或创建新对象或触发功能 出于这个原因,我需要Rust 使用Any trait获取对包含引用的结构的引用时的生存期问题,rust,lifetime,any,Rust,Lifetime,Any,我在一个小游戏中遇到了一生的问题。下面的代码表示更新循环的简化版本。 我需要容器可变引用来获取对其他游戏对象的引用或创建新对象或触发功能 出于这个原因,我需要Anytrait才能将该trait强制转换为结构,因此在我的GameObjtrait中,我添加了一个as_Any方法,但这导致了一个生存期问题 use std::any::Any; trait GameObj<'a> { fn as_any<'b>(&'b self) -> &'b (
Any
trait才能将该trait强制转换为结构,因此在我的GameObj
trait中,我添加了一个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);
}
}
}
}
我如何在不使用静态的情况下完成这项工作,或者为什么这是不可能的?任何
都是静态的,可以。因此,为了使dyn Any+'a
成为格式良好的类型,您的as_Any
方法被赋予了一个隐式'a:“static
绑定,从而导致您显示的生存期错误
如果没有此限制,您可以通过将'a
类型放入Any
并取出'static
类型来破坏安全性,因为TypeId
无法判断编译过程中不同的生存时间被删除。有关更多信息,请参阅
您应该更仔细地考虑为什么要使用Any
。这几乎不是你真正想要的。也许像存储所有不同对象类型这样简单的类型会更好地满足您的用例
如果您真的想使用
Any
,那么您需要找到一种方法使您的类型“静态”
。(或者,如果涉及线程)通常有助于实现此目的;例如,您可以让您的对象存储Rc
(或者更好地说,Rc
)而不是&'String
对于变量、方法、宏和字段,惯用的Rust使用snake\u case
<代码>大写
用于类型和枚举变量;对于静力学和常数,SNAKE\u案例
。请改用对象
和容器
。您确定需要任何
?在您的用例中,是否不可能在GameObj
trait上触发您想要的功能,而不是通过向下转换提取特定结构的相关方法?谢谢您的回答。杰普:你说得对,我经常在不同的语言之间切换,尤其是Java,所以我有时会混淆这些约定。我也考虑过这一点,但方法的数量会激增,并且不是每个对象都支持它们,例如,我可以在门上触发method open,但这对于tile GameObj来说没有意义。你不需要为每种类型实现每种方法。只要有enum GameObj{Door(Door),…}
和当前向下转换到Door
的任何位置,而只要让GameObj::Door(d)=game_obj{…}
。向下转换几乎就像“承认失败”,因为当您必须返回到具体类型时,您不能利用类型擦除,所以您最好只使用enum
。(也就是说,我怀疑你可能正在走一条笨拙而低效的设计之路,仅仅基于这个例子。我发现一个有用的原则是,在面向对象编程中,对象代表解决问题的机器的一部分,而不是问题本身的一部分。如果你是从面向对象的角度来看的,我建议你阅读,回答得好,有一点挑剔:Rc
通常比Rc
更可取,因为它具有较少的间接性,而且你不能通过Rc
进行变异,所以容量是没有意义的(同样的原因,人们不应该使用&String
)。谢谢你的回答!我想我会采用enum方法,我尝试了一个简化的更新循环,效果很好。不过它引入了一点编结代码,因为在enum上调用示例更新时,我必须使用一个包含所有使用过的游戏对象结构的大匹配。有办法吗?@Tobi Yeah,the可以为所有方法生成样板文件。谢谢,这看起来很有希望,我会尝试一下。