Home > other >  rust str slice from string
rust str slice from string

Time:01-20

"A slice is a kind of reference, so it does not have ownership."

The following code is simplified. It needs to return a slice using a match. All but one match arm return a string slice. One arm needs to add single quotations around a slice, thus we turn to using format! that returns String. The String must then convert to &str.

The error shows that the resulting slice is referenced by the temporary String in the match arm.

11 |     ret
   |     ^^^ returns a value referencing data owned by the current function

The simplified code as follows. Note we are not using literals but a &str returned from a third party crate.

fn my_func(input: &str) ->&str {
    
    let ret =
        match input {
            "a" => "Apha", // in fact, a &str from a crate
            _ => format!("'{}'", "Quoted" ).as_str(), 
        };
        
    ret
}
 

&str is desired because that &str is then pushed using push_str().

fn main() {
    let mut s = String::new();
    s.push_str(my_func("a"));
    
...

What is your recommendation for copying the str or derefencing the temp string within the match?

CodePudding user response:

You can't return a reference to a locally allocated String because the string is dropped when the function returns. There's no way to finagle your way around that. A &str is simply a bad match for the type of data you want to return.

The most straightforward fix is to return an owned String.

fn my_func(input: &str) -> String {
    match input {
        "a" => "Alpha".to_string(),
        _ => format!("'{}'", "Quoted" ), 
    }
}

Another is to return a Cow<'_, str>, which can hold either a borrowed or owned string depending on which you have. It's a bit fussy, but it does avoids unnecessary allocations. I only recommend this if efficiency is of utmost important; otherwise, just return String.

fn my_func(input: &str) -> Cow<'_, str> {
    match input {
        "a" => "Alpha".into(),
        _ => format!("'{}'", "Quoted" ).into(), 
    }
}

I'll also mention a third option -- for educational purposes, not for actual use, since it leaks memory. You can get a 'static reference to an owned object if you leak it. Leaked memory is valid for the remainder of the program since it's never freed, and thus you can in fact get a reference to it.

// Warning: Do not use! Leaks memory.
fn my_func(input: &str) -> &'static str {
    match input {
        "a" => "Alpha",
        _ => Box::leak(format!("'{}'", "Quoted").into_boxed_str()), 
    }
}

CodePudding user response:

The problem is that the arm with format!().as_str() produces an owned String, as soon as your function returns, the String is dropped and the &str reference would become invalid.

You can use std::borrow::Cow to allow a function to return both owned or borrowed strings.

CodePudding user response:

In addition to the other answers, you can also change my_func to take a parameter that tells it where to put its result instead of returning it:

use std::fmt::Write;

fn my_func(output: &mut impl Write, input: &str) {
    match input {
        "a" => write!(output, "Apha").unwrap(), // in fact, a &str from a crate
        _ => write!(output, "'{}'", "Quoted" ).unwrap(), 
    };
}

fn main() {
    let mut s = String::new();
    my_func(&mut s, "a");
}

Playground

  •  Tags:  
  • Related