Is it possible to convert a borrowed value to a reference with the static lifetime?


#1

I have a struct which has a field in the type &'static str. In order to construct the struct from any type which implements ToString, I need to convert a String to the type &'static str like this:

#[derive(Copy, Clone, Debug)]
struct Foo {
    s: &'static str,
}

impl Foo {
   fn new<T>(x: T) -> Self where T: ToString {
       Foo { s: &x.to_string() }
   }
}

fn main() {
    let foo = Foo::new(1);
    println!("{:?}", foo);
}

You can run it here http://is.gd/1qnGbN and the error is borrowed value does not live long enough. Is it possible to convert a borrowed value to a reference with the static lifetime? If not, how can I rewrite the above code? Thanks!


#2

No; you’re trying to do something Rust is specifically designed to stop you from doing because it’s a terrible idea. If that code compiled, you’d have a pointer to a string that no one owns, and as such will be destroyed the moment new finishes, leaving you with a dangling pointer.

You also can’t “extend” something you’ve borrowed so that it lives longer.

That said, if you can change Foo, you can just modify it so that s can be either a static string or an owned string:

use std::borrow::Cow;

#[derive(Clone, Debug)]
struct Foo {
    s: Cow<'static, str>,
}

impl Foo {
    fn new<T>(x: T) -> Self where T: ToString {
        Foo { s: x.to_string().into() }
    }

    fn new_static(s: &'static str) -> Self {
        Foo { s: s.into() }
    }
}

fn main() {
    println!("{:?}", Foo::new(1));
    println!("{:?}", Foo::new_static("hi!"));
}

There’s one other thing you can do, which is to deliberately leak the result of x.to_string(), ensuring it never gets destroyed, but I’m not going to provide an example of that because it’s not the sort of thing I want to encourage.


#3

Thanks for your solution using Cow. It seems that the new() method can also accept &'static str as the argument. Do we still need the new_static() method?


#4

Passing a &'static str to new defeats the whole point of using Cow: new will always allocate a String, no matter what you pass it.

If you don’t care about allocation, then you could just use String instead of Cow<'static, str>.


#5

I get the point. Thank you very much!