Understanding Strings in Rust

iamdipankarpaul

Dipankar Paul

Posted on March 23, 2024

Understanding Strings in Rust

When working with text in Rust, it's essential to understand the two primary string types: String and str. In this guide, we'll explore the differences between them and how to use them effectively.

Introduction to Strings

A string is a collection of characters. In Rust, the String type represents a growable, mutable, owned, heap-allocated UTF-8 encoded string. On the other hand, str (string slice) is an immutable view into a sequence of UTF-8 bytes, usually borrowed from a String or a string literal.

String Type (String)

A String in Rust is a mutable, UTF-8 encoded string that can grow and shrink in size. You can create a String from a string literal or from another String using the to_string method.

let s1: String = "Hello, ".to_string();
let s2: String = String::from("world!");
let s3: String = String::new(); // Dynamic empty string
let combined = s1 + &s2;

println!("{}", combined); // Prints: Hello, world!
Enter fullscreen mode Exit fullscreen mode

One other way to make a String is called .into() but it is a bit different because .into() isn't just for making a String.

fn main() {
    let s4 = "Try to make this a String".into(); 
    // ⚠️type annotations needed, consider giving `s4` a type

    let s5: String = "Try to make this a String".into();
    // ✅ Now compiler is happy with `String` type
}
Enter fullscreen mode Exit fullscreen mode

Methods on String

String has various methods for manipulating and working with strings. Some common methods include:

  • push_str: Appends a string slice to the end of the String.
  • replace: Replaces a substring with another substring.
  • to_uppercase/to_lowercase: Converts the string to uppercase or lowercase.
let mut my_string = String::from("Hello, world!");
my_string.push_str(" How are you?");
my_string = my_string.replace("world", "Rust");

println!("{}", my_string.to_uppercase()); 
// Prints: HELLO, RUST! HOW ARE YOU?
Enter fullscreen mode Exit fullscreen mode

String Slice (&str)

A str is an immutable reference to a sequence of UTF-8 bytes. It is usually seen as a borrowed form of a String or a string literal.

let s: &str = "Hello, world!";
let slice: &str = &s[0..5]; // Take a slice from index 0 to 5 (exclusive)

println!("{}", slice); // Prints: Hello
Enter fullscreen mode Exit fullscreen mode

You can even write emojis, thanks to UTF-8.

fn main() {
    let name = "😂";
    println!("My name is actually {}", name);
    // prints: My name is actually 😂
}
Enter fullscreen mode Exit fullscreen mode

Methods on str

str also has a variety of methods for manipulating and working with text. Some common methods include:

  • len: Returns the length of the string.
  • is_empty: Returns true if the string is empty.
  • starts_with/ends_with: Checks if the string starts or ends with a given substring.
let my_str: &str = "Hello, Rust!";
let my_string: String = String::from("Hello, Rust!");

println!("str Length: {}", my_str.len());
println!("String Length: {}", my_string.len());

println!("str Is empty: {}", my_str.is_empty());
println!("String Is empty: {}", my_string.is_empty());

println!("str Starts with 'Hello': {}", my_str.starts_with("Hello"));
println!("String Starts with 'Hello': {}", my_string.starts_with("Hello"));
Enter fullscreen mode Exit fullscreen mode

Transforming Between String and str

You can convert a String to a &str using the as_str method or by using the & operator. Conversely, you can convert a &str to String using the to_string method.

let my_string: String = String::from("Hello");
let my_str1: &str = my_string.as_str();
let my_str2: &str = &my_string;

println!("{}", my_str1); // Prints: Hello
println!("{}", my_str2); // Prints: Hello

let my_str: &str = "World!";
let my_string: String = my_str.to_string();

println!("{}", my_string); // Prints: World!
Enter fullscreen mode Exit fullscreen mode

Concatenating Strings

There are several ways to concatenate strings in Rust, depending on your needs:

  • Using the + operator (consumes ownership of the first string).
  • Using the format! macro (does not consume ownership of any string).
  • Using the push_str method to append a string slice to a String.
  • Using the push method to append a single character or string slice to a String.
let s1 = String::from("Hello, ");
let s2 = String::from("world!");

let combined = s1 + &s2; // Using the + operator

let combined = format!("{}{}", s1, s2); // Using the format! macro

let mut s1 = String::from("Hello,");
let s2 = String::from("world!");

s1.push_str(&s2); // Using the push_str method

let mut s1 = String::from("Hello,");
let s2 = String::from("world!");

s1.push(' '); // Adding a space(' ') Char type
s1.push_str(&s2); // Using the push method
Enter fullscreen mode Exit fullscreen mode

When concatenating strings, be aware of ownership and borrowing rules to avoid issues like moving ownership unintentionally. If you need to concatenate strings in a loop or multiple times, consider using a String and appending with push_str for better performance.

Conclusion

Understanding the differences between String and str is crucial for writing efficient and safe Rust code when working with strings. By following Rust's ownership and borrowing rules, you can manipulate strings effectively while ensuring memory safety.

💖 💪 🙅 🚩
iamdipankarpaul
Dipankar Paul

Posted on March 23, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related