Return a join of &str

I've the below function, it works correctly if I want to return x or y, but it fail to return x+y

fn test() -> &'static str {
    let x = r#"
        Hi there
    "#;
    let y = r#"
        Hi man
    "#;
    let mix = format!("{0}{1}",x,y);
    &mix
}

It gave me the below error:

error[E0515]: cannot return reference to local variable `mix`
  --> src/main.rs:26:5
   |
26 |     &mix
   |     ^^^^ returns a reference to data owned by the current function

Remember the ownership rules?

  1. Each value in Rust has a variable that's called its owner.
  2. There can only be one owner at a time.
  3. When the owner goes out of scope, the value will be dropped.

format! creates a String. You try to return a reference to this string, but the string is dropped at the end of test(), because it goes out of scope.

The usual workaround is to return a String instead of a &str:

fn test() -> String {
    // ...
    format!("{0}{1}",x,y)
}
3 Likes

What if I'm using a third party module, that required to return &str?

Then you won't be able to implement it that way.

Concatenating two strings together like you did requires the function to create a new buffer. That buffer has to be owned on the stack somewhere. If it can't just pass ownership up to its caller, then it will have to put the buffer somewhere else or get it from somewhere (like a parameter, though this function doesn't accept any, or a global or thread-local storage).

2 Likes

I'm not sure how the 3rd party module requires this. Do you need to pass test() to another function? If, for example, the third party module has a function similar to

fn accept<'a>(f: impl FnOnce() -> &'a str) {
    // ...
}

and you want to do accept(test), then you can use a closure instead of test:

let mut mix = String::new();

accept(|| {
    let x = r#"
        Hi there
    "#;
    let y = r#"
        Hi man
    "#;
    mix = format!("{}{}", x, y);
    &mix
});

The closure can return &str because mix is defined outside the closure, so it lives long enough.

2 Likes

In most cases, &'static str means just string literal or its substring, not a runtime-generated string.

1 Like

&'static str basically means only string literals are allowed, and any dynamically created strings are not supported. So if a third party module has such requirement, then the third party is forbidding you from using format!.

If you must, then Box::leak(format!("foo").into_boxed_str()) will transform String into &'static str, but don't do it. That's a hack. The program will never free that memory.

Returning &str is very limiting for functions. Error::description() in Rust's stdlib made that mistake, which made the whole function useless, and it got removed as a result.

The function should return String to allow dynamically created strings. It may return Cow<'static, str> to allow either &'static str or String without having to clone the str.

6 Likes