Use lifetime for the first time, need help!


#1

I started to learn and use Rust few months ago. I never understand lifetime in Rust, and tend to avoid using references. But this time I can not avoid it any more, and there appear an error that I do not know how to solve. The code is here:

https://play.rust-lang.org/?gist=2590aeec13d12b1d14dc32a7998ba19c&version=stable

Is that way of using reference (of course, with some modifications) possible?
How to tell Rust that all_streams will always be there so that references in common_parts will always valid?
Or how… oh… I don’t know how! :frowning_face:

Please help! Thank you very much!


#2

The reason this doesn’t work is because your System owns the Stream (you push it into the vec). System is also parameterized by a lifetime, 'system, that’s picked by the caller/user of it - the CommonPart holds references to something the caller has determined a lifetime for. When you try to insert a reference to the Stream that you just became an owner of, there’s no way to meet that lifetime constraint - the lifetime of the Stream is equal to System, and not to a lifetime chosen by the caller. It’s morally equivalent to defining a struct Foo<T> {items: Vec<T>}, caller using it as Foo<i32>, and you trying to stick a String into the vec. Whether with generic lifetime parameters or generic type parameters, you cannot use incompatible types (this is more obvious with generic type params, but lifetimes are very much analogous at its core).

Ultimately, it seems like you’re attempting to create a self-referential struct - Rust doesn’t allow this. You can either have System take references from outside, or wrap the items in an Rc (to share ownership across several places), or use a crate like rental.


#3

rental is not for newcomer (or not for me? read its docs, read its example, read its test codes… understand little, and completely not know how to apply to my problem).

Rc and RefCell (I need to modify Stream via reference in CommonPart) have some overhead. I have to iterate through these Vec again and again intensively, hence I don’t want to give up performance here. I know that losing some performance is better than walking with bare feet into the dark wild. But I have another big reason as I mentioned in the original post:

How to tell Rust that all_streams will always be there so that references in common_parts will always valid?

Yes, when I know the fact that all references will always be valid why not go for some unsafe-Rust code. I decide to read some docs about unsafe-Rust (never read it before), and happy with my choice.

Some words for newcomers like me. If you are able to reason and sure about the safety of your piece of code, don’t be afraid of unsafe code. When you feel perfectly safe in an unsafe-block, unsafe is your friend, otherwise just stay away from it.


#4

What happens if the Vec holding the streams resizes (reallocates) and the streams are moved to different memory location? Your CommonParts are left holding dangling references (assuming you switched to raw pointers) to those streams.


#5

Thank you for your warning! In this case, the number of streams can be counted before creating them. I think creating Vec::with_capacity will solve the problem? I seem over confident when trying unsafe-code! I should be more careful! Thanks again!


#6

typed_arena crate could be a better choice. It guarantees that references to objects allocated in the arena are valid for the entire lifetime of the arena.


#7

I actually think Vec::into_boxed_slice is better to enforce the fixed size aspect.


#8

Yeah if you can keep the storage fixed then this concern goes away. The hard part about things like this isn’t getting the initial code to work but keeping it working as code churns and these little safety assumptions erode away. Compiler (for all intents and purposes) turns its head away from unsafe and won’t be able to help.

You mentioned performance being a concern but perhaps you should write a safe version and check it first? It might be good enough. You can always cut corners later.