In Rust, handling text is a common task, and understanding when to use `&str` and when to use `String` is key — it could lead to more efficient code when done right or otherwise when misused.
When you have passed the stage of just getting your Rust code to work you want to make it more efficient. And you want to understand how string really works.
While Rust has only one string type in the core language, which is the string slice `str` that is usually seen in its borrowed form `&str`, it also has the `String` type, which is provided by Rust’s standard library rather than coded into the core language — it is a growable, mutable, owned, UTF-8 encoded string type — which technically allows you to create, modify, and own text data.
When should you use `&str` instead of the `String`?
- Use `&str` when you don’t plan to modify the text. If you’re working with read-only text, using `&str` can be more memory-efficient as the string slice does not involve memory allocation and deallocation
- When you need a string that only hold references to values already in memory.
- Use string slice if you don’t need to transfer ownership of a text to a function or variable, it doesn’t own the string, it only holds a reference to a memory address that contains the string.
Note: A string literal for example `name = Eze;` is by default a string slice.
Here is an example of how you can use a string slice:
fn print_message(message: &str) {
println!("{}", message);
}
fn main() {
let greeting: &str = "Hello, Rust!"; // string literal, also a string slice
print_message(greeting);
let greeting2: String = String::from(greeting); // String
print_message(&greeting2);
}
In this example, we want our function to accept a string slice. So, in this first instance we collected a string literal and passed it to the function directly, of course, because like we’ve already established, string literals are also string slice.
When should you use a `String`
The simple and short answer is – to use String when you need to modify, build, or own text data, especially if you need dynamic string manipulation like the example below:
fn create_greeting(name: &str) -> String {
let mut greeting = String::from("Hello, ");
greeting.push_str(name);
greeting
}
fn main() {
let person = "Alice";
let personalized_greeting = create_greeting(person);
println!("{}", personalized_greeting);
}
Things to note:
A String contains heap-allocated bytes. While working with String, you’ll most likely allocate and deallocate memory which might come with a small cost especially if you are working with a large string. When you use the `format!` macro, you perform a memory allocation. Smartstring seems to help you find a way around this:
Smartstring are String type that’s source compatible with `std::string::String`, uses exactly the same amount of space, doesn’t heap allocate for short strings (up to 23 bytes on 64-bit archs) by storing them in the space a `String` would have taken up on the stack, making strings go faster overall.
Both string types are very relevant in their own capacity — there is more to learn about strings in Rust. The Rust Book is a great place to learn more https://doc.rust-lang.org/book/ch08-02-strings.html. If this was helpful please share.