Returns a value referencing data owned by the current function

Hi folks, a minimum buggy example is as follows:

fn main() {
  S::f1();
}

struct S<'a> {
  s: &'a str
}

impl<'a> S<'a> {
  fn f1() -> Self {
    let v = vec![]; // some vector that cannot be <'static>
    S::f2(std::str::from_utf8(&v).unwrap())
  }

  fn f2(s: &'a str) -> Self {
    // assume very long function body here
    S { s }
  }
}

I'm trying to create an instance of struct S without converting &str to String.
The example is pretty straightforward, so I assume I do not need to further explain.

While compiling, I got this error:

12 |     S::f2(std::str::from_utf8(&v).unwrap())
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^--^^^^^^^^^^^
   |     |                         |
   |     |                         `v` is borrowed here
   |     returns a value referencing data owned by the current function

Is there a way to fix this problem without using String? Or do I have to use String?

Thx!

What are you making?

You will likely have to use either String or Cow<'_, str>

Hi, I'm trying to create an instance of struct S using S::f1() but I don't want to `String. Is it possible?

What is S? Without knowing more about your code, I can't help.

With just ths information that you gave, you must use String because you can't return a reference to local variables.

You could use Cow so that f2 can return a str while f1 returns a `String°

Note: you can convert a Vec<u8> directly to a String

Hi, S is a struct define in code from line 4-6.

I can read that, this code is clearly some placeholder code for your actual problem. What is your actual problem?

You can't create v inside f1 because it'll be destroyed when the function returns. The calling function would either need to pass a &[u8] into f1 or S will need to own the string.

Why?

Note that either way you'd end up creating a heap-allocated object. A String and vec![] both have the same amount of overhead, so (if the code compiled) it would be equivalent to the S holding a String in terms of performance and memory usage anyway.

I'm guessing your real code is a lot more complicated than the example above, in which case I'd recommend you try to figure out which components should logically own what. Normally you'll use lifetimes for a temporary object which is borrowing some data while you do an operation.

2 Likes

@KrishnaSannasi @KrishnaSannasi Thanks for your time anyway!
Here is a brief explanation of what I actually want.

In my real problem:

  • f1() takes a TcpStream as a parameter, and I was trying to read the data from the TcpStream and parse the data into a struct (I assume what struct S really is does not make this problem simpler)

  • f2() takes a &'a str as a parameter, and I was trying to parse the string directly into a struct

Since the data read from TcpStream could be stored in a Vec<u8> which can then be converted into a &str, I wrote S::f2(temp_string) as the last line of code in f1().

The temp_string caused this problem because it was created from std::str::from_utf8(&vec).

btw, I was able to compile my code if f1() takes an extra parameter - the vector buffer - so that f1() does not need to create the vector locally.

You should use Cow fof the reasons I listed above. In f1 use Cow::Owned and in f2 use Cow::Borrowed

You can't return references to local data, so you will need to convert to a String for f1.

For f2 you are given a &'a str to work with, so you don't need to allocate by using Cow

2 Likes

BTW, will it be considered a good practice for this situation if I pass an extra buffer variable to f1()?

The vector buffer will still be allocated on the heap though.

I mean, if you have a reallocation you want to reuse, go ahead, but if you don't have one, there isn't much reason.

1 Like