问题
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