2

I'm learning Rust and learned, that for making an expandable string or array, the String and Vec structs are used. And to modify a String or Vec, the corresponding variable needs to be annotated with mut.

let mut myString = String::from("Hello");
let mut myArray = vec![1, 2, 3];

My question is, why would you use or declare an immutable String or Vec like

let myString = String::from("Hello");
let myArray = vec![1, 2, 3];

instead of a true array or str literal like

let myString = "Hello";
let myArray = [1, 2, 3];

What would be the point of that, does it have any benefits? And what may be other use cases for immutable String's and Vec's?

Edit:

Either I am completely missing something obvious or my question isn't fully understood. I get why you want to use a mutable String or Vec over the str literal or an array, since the latter are immutable. But why would one use an immutable String or Vec over the str literal or the array (which are also immutable)?

Codey
  • 1,131
  • 2
  • 15
  • 34
  • Does this answer your question? [What are the differences between Rust's \`String\` and \`str\`?](https://stackoverflow.com/questions/24158114/what-are-the-differences-between-rusts-string-and-str) – smitop Dec 10 '21 at 17:53
  • By the way, the type name is `Vec` and not `Vector`. – Herohtar Dec 10 '21 at 17:53
  • Does this answer your question? [What are the differences between \[\], &\[\], and vec!\[\]?](https://stackoverflow.com/questions/57848114/what-are-the-differences-between-and-vec) – Herohtar Dec 10 '21 at 17:54
  • If the string isn't known at compile time, it must be stored somewhere. You can't own a `str`. `String` is a convenient solution to own a string when you need a `&str`. – Denys Séguret Dec 10 '21 at 17:58
  • 1
    Important: https://stackoverflow.com/q/28587698 ; That the value of type `String` or `Vec` is behind an immutable variable does not necessarily mean that its value will never be modified: it could be moved into a new context where it will. – E_net4 Dec 10 '21 at 18:04
  • @Herohtar no, because in he explains '[use `Vec` ...] in order to be able to change its size during runtime'. But if the `Vec` variable is immutable, is there any other reason to use `Vec`? – Codey Dec 10 '21 at 18:10
  • @Smitop that somewhat answers the question but not completely. He states that you use `String` 'when you need to own or modify your string data'. That's what I was looking for. If I don't want to modify my string data (i. e. not annotated with `mut`), the other reason to use `String` is when I want to own the string data. Why would I want to do that? – Codey Dec 10 '21 at 18:13
  • @DenysSéguret could you elaborate on that? Why would I want to own a `String` instead of `&str` bound to a variable? – Codey Dec 10 '21 at 18:25
  • @Codey A `&str` is a reference to some other place in memory. This place must exist. If the string isn't static, the easiest solution is to reference a `String`. – Denys Séguret Dec 10 '21 at 18:28

2 Answers2

2

You might then do something with that string, for example use it to populate a struct:

struct MyStruct {
    field: String,
}

...

let s = String::from("hello");
let mut mystruct = MyStruct { field: s };

You could also, for example, return it from a function.

lkolbly
  • 1,140
  • 2
  • 6
  • Yes but I could use the `str` literal for this as well right? Are there any advantages of using this immutable `String` vs. the `str` literal in this case? – Codey Dec 10 '21 at 18:14
  • You could use a &'static str as well, but only if MyStruct will never mutate `field`. If you're never going to mutate them, then there's no reason to use a String or Vec. – lkolbly Dec 10 '21 at 18:36
  • 1
    Ok I understand, this is a very good example. With your implementation I could still modify the string with `mystruct.field.push_str(" world")` even though `s` is immutable. – Codey Dec 10 '21 at 18:40
2

One use case could be the following:


fn main() {
    let text: [u8; 6] = [0x48, 0x45, 0x4c, 0x4c, 0x4f, 0x00];
    let converted = unsafe { CStr::from_ptr(text.as_ptr() as *const c_char) }.to_string_lossy().to_string();

    println!("{}", converted);
}

This is a bit constructed, but imagine you want to convert a null terminated C string (which might come from the network) from a raw pointer to some Rust string, but you don't know whether it has invalid UTF-8 in it. to_string_lossy() returns a Cow which either points to the original bytes (in case everything is valid UTF-8), but if that's not the case, it will basically copy the string and do a new allocation, replace the invalid characters with the UTF-8 replacement character and then point to that.

This is of course quite nice, because (presumably) most of the time you get away without copying the original C string, but in some cases, it might not be. But if you don't care about that and don't want to work with a Cow, it might make sense to convert it to a String, which you don't need to be mutable afterwards. But it's not possible to have a &str in case the original text contains invalid UTF-8.

Hellstorm
  • 562
  • 4
  • 23