error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/main.rs:42:52
|
42 | for frame_object in self.proto_spec.frames.iter()
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined on the method body at 38:33...
--> src/main.rs:38:33
|
38 | pub fn init_decoder_hashmap(&mut self)
| ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:42:29
|
42 | for frame_object in self.proto_spec.frames.iter()
| ^^^^^^^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 36:6...
--> src/main.rs:36:6
|
36 | impl<'a> Decoder<'a>
| ^^
note: ...so that the expression is assignable
--> src/main.rs:47:28
|
47 | self.decoder_map = map;
| ^^^
= note: expected `HashMap<_, &'a FrameObject>`
found `HashMap<_, &FrameObject>`
I have cleaned up the code a bit. You can look at the code on the playground.
Unfortunately, as you can see, Decoder is a struct that stores a reference into itself (it stores the ProtoSpec, and also references to FrameObject, which are actually owned by the ProtoSpec you are storing in the Decoder).
I don't know of any simple way to do this, which doesn't involve using unsafe or an external crate.
You are better off not storing proto_spec in Decoder. The following playground link demonstrates a way of doing this.
Instead of referencing your FrameObject directly in your HashMap, you can reference it via index into the vector of ProtoSpec.
Keep in mind that there is now one more level of indirection, so the logic should be well encapsulated to provide a good API (e.g. in my example, the decoder_map of Decoder is now private).
Absolutely! And in fact, if you know that the ProtoSpec is never going to change, then this solution is both more convenient and represents the problem better.
One more time: Playground
Is it not possible to use an fn init(&'a mut self) function in a constructor (fn new_from(proto_spec: ProtoSpec) -> Driver<'a>) ?
You cannot because you are still effectively storing a reference to a field of a struct within that struct. Then, you are returning the struct by value, that is, you are moving the struct, while it is still borrowed (albeit, it is borrowed within itself).
Shifting around the code to different structs won't change the fact, because the lifetime system is immune to that.
Also, please could you rustfmt your code? Rust-devs are so used to seeing code formatted in exactly one fashion (unlike C++/C/Java) that it's rather jarring to see anything else.
In general, on a type Foo<'a> a method fn bar(&'a mut self) is a very bad idea / huge antipattern. It’s almost unusable, and almost never what you actually want. The type of self in such a method would be &'a mut Foo<'a>.
The value of type Foo<'a> can only exist for as long as the lifetime 'a is, so that a &'a mut Foo<'a> reference borrows such a value for its entire (remaining) existence. You cannot do anything with that value after calling such a method bar on it, since it’s perpetually exclusively borrowed. You cannot call any other method after bar, be it a &mut self method or a &self one; you cannot move the value anymore, in particular you cannot return it either, so: no, you can’t use fn init(&'a mut self) function in a constructor fn new_from(proto_spec: ProtoSpec) -> Driver<'a>, and “replace &mut self with &'a mut self as parameter of init_decoder_hashmap” is a terrible suggestion.
I don't think you are appreciating the actual problem here.
You can't store a reference to a non-static local variable and then return it. This never works in Rust (or in C or in C++, for that matter). This never works because when you return the reference, the variable the reference points to ceases to exist.
You can't store a reference to a field of a struct within a struct without any non-trivial amount of effort. The idiomatic way of storing references to something in a struct is to store that something in a different struct, which outlives the one storing the reference,