Enum temporary value and lifetimes


#1

Hey,

I am a new rust user just getting grips with the language. My code does not compile because I cannot figure out how to assign a lifetime to an enum (I think anyway). I would really appreciate any pointers :stuck_out_tongue:

enum Security {
    WEP,
    WPA1,
    WPA2,
}

pub struct AccessPoint<'a> {
    ssid: String,
    signal: u8,
    security: &'a [Security],
}

pub fn scan<'a>() -> Result<&'a[AccessPoint<'a>], String> {
    let ap1 = AccessPoint {
        ssid: "ap1".to_owned(),
        signal: 60,
        security: &[Security::WEP],
    };
    let ap2 = AccessPoint {
        ssid: "ap2".to_owned(),
        signal: 92,
        security: &[Security::WPA1, Security::WPA2],
    };
     
    Ok(&[ap1, ap2])
}

I have put into the rust playground here


#2

Hey there,

what you are trying to achieve is impossible.
In scan you create AccessPoints that reference to Securitys.

But nobody owns these Securitys; they are created on the stack in scan and are thus dropped as soon as scan finishes.

(Have a look at the book for a more thorough explanation.)

What you can do though, is to let the AccessPoints own their Securitys using Vec:

pub struct AccessPoint {
    ssid: String,
    signal: u8,
    security: Vec<Security>,
}

(see full version on playground )


#3

Great, thank you!

Does this work because vectors are always stored on the heap?


#4

Well, the data of vectors is stored on the heap. But yes, that is the reason why it works.


#5

While it’s true that vectors’ data is always stored on the heap (and it would be hard to implement vector differently), it’s not the actual reason why it works.

It works because Vec contains the data itself.

Everytime you see a & in type, you can image it’s just a sign saying “well, the actual data is actually over there”. So everytime you see & in a struct definition, you need to think “The data will be somewhere else. Am I sure this somewhere else will exist for the time this struct will be used?”. Similar thinking goes for & in return values.

And also, you don’t have to think that your code didn’t work because you had something on the stack. I consider stack an implementation detail (although important one). It didn’t work, because it was a temporary value. Here are two rules for temporaries: unnamed values die at nearest semicolon (or end of block if there’s no ;), named values (created with let) die at the end of block.

I hope my explanation didn’t complicate things further :slight_smile:


#6

Hey @krdln

Thanks for that, it makes things much clearer :stuck_out_tongue: and leads me onto another question(s).
How would I create a non-temporary value? Is it possible to write my function above to return a borrowed slice rather than a vector? Is using a vector like we have here the rust way of doing things (given the vector is not going to be changed once its returned) ?

Thanks


#7

If you want to return any dynamic content (which you do), then it’s impossible, Vec is idiomatic and simpler way to do it. You can only return a reference if the referred values existed before function was even called (that usually means static or something like trim does).


#8

Cool, thanks for clearing that up