23

I have a lifetime/borrowing error from the Rust compiler that I can't get my head around. The problem seems to be that Rust assumes that when an argument is passed to a function that returns a reference to a static value, the argument reference must also be static.

#[derive(Debug)]
struct TestThingy<'a> {
    label: &'a str,
}

const TEST_VALUES: [TestThingy; 3] = [
    TestThingy { label: "one" },
    TestThingy { label: "two" },
    TestThingy { label: "three" },
];

pub fn value_for_num(num: &str) -> Option<&'static TestThingy> {
    TEST_VALUES.iter().find(|value| value.label == num)
}

pub fn test_out_thingy() {
    let tmp_val = String::from("two");
    if let Some(test_thingy) = value_for_num(&tmp_val) {
        println!("test_thingy: {:?}", test_thingy);
    }
}

fn main() {
    test_out_thingy();
}

Rust errors with: error[E0597]: `tmp_val` does not live long enough - E0597 refers to when a value gets dropped whilst its still borrowed, which isn't happening here - I don't know how to convince Rust of that though.

The idea behind this code, for more context, is it's a lookup mechanism for compile-time/static config (in my codebase they are Syntax values, matched on the basis of a provided filename &str). So the provided argument genuinely does not live as long as the static config, but I don't understand why that's a problem. The returned value doesn't/can't contain the argument as a reference, so I'm super unclear why this borrowing error is happening.

William Roe
  • 559
  • 1
  • 5
  • 14

1 Answers1

20

The problem lies in the function signature of value_for_num.

You indicate that you return a static reference to a TestThingy but have no indication what kind of references that TestThingy<'x> might hold. Thus the compiler assumes that the unspecified input reference lifetime may be tied to the unspecified output lifetime of references inside the TestThingy.

i.e. the compiler sees this:

pub fn value_for_num<'a>(num: &'a str) -> Option<&'static TestThingy<'a>>

If you change the signature to specify that the contained references are also static then it compiles.

pub fn value_for_num(num: &str) -> Option<&'static TestThingy<'static>>
turbulencetoo
  • 3,447
  • 1
  • 27
  • 50