0

This rust code doesn't work. Is there any detailed explanation for why? It gives the error "cannot return reference to temporary value"

trait NonInherited {
    fn get_type(&self) -> &str;
}

struct Inherited {
    val: usize,
}

impl NonInherited for Inherited {
    fn get_type(&self) -> &str {
        return "inherited";
    }
}

fn helper(list: &mut [usize; 2]) -> &'static dyn NonInherited {

    // works
    //return &Inherited {val: 3};

    // does not work
    return &Inherited {val: list[1]}; // Error is here
}

fn main() {
    let mut a: [usize; 2] = [1, 7];
    println!("{}", helper(&mut a).get_type());
}
  • Does this answer your question? [Why can I return a reference to a local literal but not a variable?](https://stackoverflow.com/questions/50345139/why-can-i-return-a-reference-to-a-local-literal-but-not-a-variable) – Chayim Friedman Jan 07 '22 at 10:45

2 Answers2

1

My understanding is that Inherited { val: 3 } is a constant struct expression that is evaluated during compilation, however, Inherited { val: list[1] } is dynamic which is evaluated during runtime.

As described in Rust reference on Constant Evaluation, constant expressions do not cause any drop() to be run, thus, its value is not temporary.

0x00A5
  • 1,462
  • 1
  • 16
  • 20
  • So the compiler knows how long `3` will be alive. But it can't tell how long `list[1]` will be alive? – Basketball Person Jan 04 '22 at 14:47
  • @Basketball Person it's that the 3, being constant data, allows all of the instances of inherited returned to be folded to a single instance with static lifetime. (Like string literals). References to this instance can be passed around freely, because it will always be there. With a dynamic value like list, each value is a unique object with its own independent lifetime. And that lifetime is the method helper. So references from outside that lifetime are clearly invalid. – user1937198 Jan 05 '22 at 19:09
0

The problem here is that the Inherited struct is created on the stack in the function helper, and then a reference to this stack-resident object is being returned. That's a problem because the lifetime of the Inherited struct is only for the scope of the helper function.

You can fix this by returning the created struct itself instead of a reference to it. Below is a simple working example, with some of the type names changed for clarity. Notice that the list variable does not need to be mut.

trait SomeTrait {
    fn get_type(&self) -> &str;
}

struct SomeStruct {
    val: usize,
}

impl SomeTrait for SomeStruct {
    fn get_type(&self) -> &str {
        return "overridden";
    }
}

fn helper(list: &[usize; 2]) -> impl SomeTrait {

    // works
    return SomeStruct {val: list[1]};
}

fn main() {
    let a: [usize; 2] = [1, 7];
    let b = helper(&a);
    println!("Type is {}", b.get_type());
}
Anthony DeRosa
  • 897
  • 7
  • 6