Assigning to a previously empty string


#1

Hello,

I have just started with Rust, and I have just reached the end of the section on control flow in the Rust Programming Language Textbook.
I have been playing around with some of the concepts that have been introduced thus far, but I have ran into an issue with strings.

I might be a bit… erm… Rusty (ahem*), but I think in C++ I could do something like:

std::string my_string = "";
my_string = "This is my amazing string.";

With Rust, when I try:

let mut my_string = String::new();
my_str = "This is my amazing string";

I get:

"my_string = "This is my amazing string.";
expected struct `std::string::String`, found reference
help: try using a conversion method: `"This is my amazing string.".to_string()`"

It found a reference, and I need to try converting my_string to a string?
In the examples so far in the textbook, it appears that the original empty string is just shadowed. Something like:

let mut my_string = String::new();
let mut my_string = "This is my amazing string.";

In Listing 2-5 from the textbook, it actually replaces the string with a new string:

let mut guess = String::new();
Everytime it loops back around, but I guess the principle is the same?

Some of these concepts are new to me, so I appreciate your help (I am currently only up to the section on ownership, so any concepts beyond this would not be familiar to me).

*I am aware this pun has probably been used ad nauseum, I apologise profusely.


#2

The issue here is the string literal there has a type &'static str, which is a string slice that lives for the life of the program (all string literals are like that). So what you want is to make that string literal a String, which is a dynamically allocated and an owned value:

let mut my_string = String::new();
my_string = "This is my amazing string".into();

The into() converts the string slice to a String and now the types match up.


#3

Hi vitalyd,

Thankyou for the information. This is not something that has come up in the textbook, yet; I am glad to know, however, that it was not something covered already and that I have missed; otherwise I would be going back and re-reading everything!

Many thanks!


#4

In C++ terms, String::new() is std::string, but &str/"…" is std::string_view.


#5

I’d like to point out an additional nuance: C++ supports copy-assignment and move-assignment operators. Rust’s assignment is always a move-assignment operator and is not customizable. @vitalyd’s solution is actually equivalent to

std::string my_string = "";
my_string = std::string("This is my amazing string");

where the second line allocates a string whose allocated buffer is transferred to my_string via the C++ r-value/move assignment operator. In the example you provided, this made no practical difference since the string was initially empty/unallocated. However, it makes a difference if my_string already has an allocated buffer.

std::string my_string = "foo";

// Overwrites "foo" using copy-assignment and does not allocate
// additional memory.
my_string = "bar";

// Allocates a new string with "baz" and then replaces my_string's
// pointer to point to it.
my_string = std::string("baz");

The latter is clearly less efficient for this scenario. Here are the rust equivalents so that you can pick as appropriate.

let mut my_string = "foo".to_string();

// Overwrites already-allocated buffer with "bar".
my_string.clear();
my_string.push_str("bar");      // or: my_string += "bar";
// On nightly, these two lines can be replaced with:
my_string.splice(0.., "bar");

// Allocates a new string with "baz" and then replaces my_string's
// pointer to point to it.
my_string = "baz".to_string();