简体   繁体   中英

rust str slice from string

"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?

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()), 
    }
}

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM