简体   繁体   中英

What is the difference between &str and &String

I'm walking through Microsoft's Rust tutorial here , which is about

implement the copy_and_return function so that it returns a reference to the value inserted in the vector

Solution is given here , but it's different from mine in that it used &String as return type while I used &str.

// standard solution
fn copy_and_return<'a>(vector: &'a mut Vec<String>, value: &'a str) -> &'a String {
    vector.push(String::from(value));
    vector.get(vector.len() - 1).unwrap()
}
// my solution
fn copy_and_return<'a>(vector: &'a mut Vec<String>, value: &'a str) -> &'a str {
    vector.push(String::from(value));
    return value; // simply return value
}

fn main() {
    let name1 = "Joe";
    let name2 = "Chris";
    let name3 = "Anne";

    let mut names = Vec::new();

    assert_eq!("Joe", copy_and_return(&mut names, &name1));
    assert_eq!("Chris", copy_and_return(&mut names, &name2));
    assert_eq!("Anne", copy_and_return(&mut names, &name3));

    assert_eq!(
        names,
        vec!["Joe".to_string(), "Chris".to_string(), "Anne".to_string()]
    )
}

In addition to the return type, another difference between mine and the standard solution is that I simply returned the parameter value , while the standard solution used complicated way vector.get(vector.len() - 1).unwrap() .

I'm wondering if there's anything wrong with my solution that the tutorial takes another way?


While @Masklinn provided a great answer to my question, it's a bit specific to the example I gave but not directly addressing the title What is the difference between &str and &String .
I found this discussion to be quite informative:

Basically a String wraps and manages a dynamically allocated str as backing storage. Since str cannot be resized, String will dynamically allocate/deallocate memory. A &str is thus a reference directly into the backing storage of the String, while &String is a reference to the “wrapper” object. Additionaly, &str can be used for substrings, ie they are slices. A &String references always the whole string.

Chapter 4.3 of the Rust book also helps

I'm wondering if there's anything wrong with my solution that the tutorial takes another way?

I don't think there's anything wrong per se, yours might even match the function name better depending how its interpreted: are you supposed to copy and return the original, or copy and return the copy? Yours is the first pick, theirs is the second.

It's made irrelevant by the lifetimes, but this does make a difference to program behaviour: in the "official" solution, the result is a reference to the value inserted into the Vec , meaning it will be "live" for as long as the vector is (at least assuming the vector is not otherwise modified).

You can see the difference if you replace value: &'a str by value: &'_ str (aka "a lifetime you don't care about but is different from 'a ): the official solution still compiles, yours does not.

Though note that the official could just as well return &'a str regardless:

fn copy_and_return<'a>(vector: &'a mut Vec<String>, value: &'_ str) -> &'a str {
    vector.push(String::from(value));
    vector.get(vector.len() - 1).unwrap()
}

The official solution is hardly great through eg

vector.get(vector.len() - 1)

is a complicated way of writing

vector.last()

but it might be that they just don't want to overwhelm the reader with advanced APIs or something, I could not say.

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