[SOLVED] Can the field of a struct be a reference on another field of the same struct?


#1

The following code won’t compile:

struct Foo<'a> {
    my_string: String,
    my_ref: &'a str
}

impl<'a> Foo<'a> {
    fn new() -> Foo<'a> {
        let s = String::from("this is a test");
    
        Foo {
            my_string: s,
            my_ref: &s[1..4],
        }
    }
}

with the error borrowed value must be valid for the lifetime 'a as defined on the impl at ...

Aren’t the lifetimes supposed to be compatible since both fields belong to the same struct? If s is moved, shoudn’t the reference point on the moved value?

Is there anything I’m completely missing? Any way to work around that?


#2

A reference is an absolute memory address, so moving Foo would have to update the reference address too. A move in Rust is just a simple memory copy that disallows further access to the original. Technically it’s true, the actual heap location of the string won’t change in a move, but the Rust type system can’t express that. Another problem here is that mutating my_string might invalidate the reference.

You might like the rental crate, although there are still limitations noted in the README. This also relies on stable_deref_trait to prove properties like the fixed string location.


#3

Another problem here is that mutating my_string might invalidate the reference.

That’s exactly what I was missing, now I get the problem. Thanks a lot!


#4

If my_ref always references my_string but at varying start and end characters, you could store the start and end indices, rather than a reference.


#5

To add to @aaronm04’s suggestion, you can make a smart ptr wrapper like newtype (if you want the deref coercion feature): example


#6

@vitalyd very nice! How did you know to add this?:

String: std::ops::Index<T, Output = str>

#7

This bit allows use of the different range types (eg Range, RangeInclusive), which range syntax desugars into. That’s what the T type param represents, really.

Does that answer your question or were you asking about something else there?


#8

Yes, that makes sense. Thanks!