Why aren't struct expressions and tuple struct expressions equivalent for choosing temporary value lifetimes?


#1

This was a surprise to me:

#![allow(dead_code, unused_variables)]

fn temp() -> i32 { 42 }

struct SomeStruct<'a> { foo: &'a i32 }
struct OtherStruct<'a>(&'a i32);

fn main() {
    // This is okay.
    let x = &10;
    
    // This is okay, too.
    let y = SomeStruct { foo: &temp() };
    
    // error: borrowed value does not live long enough
    // let z = OtherStruct(&temp());
    
    // error: borrowed value does not live long enough
    // let w = Some(&temp());
}

(I put this in a playpen if you want to try it out.)

I would expect SomeStruct and OtherStruct to be treated similarly when choosing a lifetime for the temporary lvalue generated for the reference to point to. To the extent that enum variants are construction expressions too, I would expect the last case to work as well.

Is this a consequence of Rust treating tuple structure constructors and variant constructors as functions? Does Rust see the third and fourth cases as equivalent to this?

let bleah = f(&temp());

#2

Interesting observation. It’s as if this list must be taken very literally and the tuple struct and enum cases have fallen through the cracks :wink:


#3

Right! I came across my list by trying to generalize what I found in the Guide and being surprised.


#4

The immediate reason is simple, the constructor for OtherStruct is just a function, so it obeys function rules, unfortunately.