Strings: &str for string slice and String for owned string
Rust has two string types, a string slice (&str) and an owned string (String).
We’re not going to dictate when you should use which one, but we’ll show you how
to identify and create them, as well as use them.
Further information
- Strings: Storing UTF-8 Encoded Text - The Rust Programming Language
- rustlings-solutions-5/strings at main · gaveen/rustlings-solutions-5
Rustlings
strings1: String -> to_string()
// strings1.rs // Make me compile without changing the function signature! // Execute `rustlings hint strings1` or use the `hint` watch subcommand for a hint. // I AM NOT DONE fn main() { let answer = current_favorite_color(); println!("My current favorite color is {}", answer); } fn current_favorite_color() -> String { "blue" }
Hint
The current_favorite_color function is currently returning a string slice with the 'static
lifetime.
We know this because the data of the string lives in our code itself – it doesn’t come from a file or user input or another program – so it will live as long as our program lives.
But it is still a string slice. There’s one way to create a String by converting a
string slice covered in the Strings chapter of the book, and another way that uses the From
trait.
strings2: &str -> as_str()
// strings2.rs // Make me compile without changing the function signature! // Execute `rustlings hint strings2` or use the `hint` watch subcommand for a hint. // I AM NOT DONE fn main() { let word = String::from("green"); // Try not changing this line :) if is_a_color_word(word) { println!("That is a color word I know!"); } else { println!("That is not a color word I know."); } } fn is_a_color_word(attempt: &str) -> bool { attempt == "green" || attempt == "blue" || attempt == "red" }
Hint
Yes, it would be really easy to fix this by just changing the value bound to word to be a
string slice instead of a String, wouldn’t it?? There is a way to add one character to line
9, though, that will coerce the String into a string slice.
strings3
// strings3.rs // Execute `rustlings hint strings3` or use the `hint` watch subcommand for a hint. // I AM NOT DONE fn trim_me(input: &str) -> String { // TODO: Remove whitespace from both ends of a string! ? ? ? } fn compose_me(input: &str) -> String { // TODO: Add " world!" to the string! There's multiple ways to do this! ? ? ? } fn replace_me(input: &str) -> String { // TODO: Replace "cars" in the string with "balloons"! ? ? ? } // convert unit tests to main fn main() { fn trim_a_string() { assert_eq!(trim_me("Hello! "), "Hello!"); assert_eq!(trim_me(" What's up!"), "What's up!"); assert_eq!(trim_me(" Hola! "), "Hola!"); } fn compose_a_string() { assert_eq!(compose_me("Hello"), "Hello world!"); assert_eq!(compose_me("Goodbye"), "Goodbye world!"); } fn replace_a_string() { assert_eq!(replace_me("I think cars are cool"), "I think balloons are cool"); assert_eq!(replace_me("I love to look at cars"), "I love to look at balloons"); } trim_a_string(); compose_a_string(); replace_a_string(); } #[cfg(test)] mod tests { use super::*; #[test] fn trim_a_string() { assert_eq!(trim_me("Hello! "), "Hello!"); assert_eq!(trim_me(" What's up!"), "What's up!"); assert_eq!(trim_me(" Hola! "), "Hola!"); } #[test] fn compose_a_string() { assert_eq!(compose_me("Hello"), "Hello world!"); assert_eq!(compose_me("Goodbye"), "Goodbye world!"); } #[test] fn replace_a_string() { assert_eq!(replace_me("I think cars are cool"), "I think balloons are cool"); assert_eq!(replace_me("I love to look at cars"), "I love to look at balloons"); } }
Hint
There’s tons of useful standard library functions for strings. Let’s try and use some of them: String in std::string - Rust!
For the compose_me method: You can either use the format! macro, or convert the string
slice into an owned string, which you can then freely extend.
solution
fn trim_me(input: &str) -> String { // Remove whitespace from the beginning and the end of a string! input.trim().to_string() } fn compose_me(input: &str) -> String { // Add to the string! There's multiple ways to do this! input.to_owned() + " world!" } fn replace_me(input: &str) -> String { // Replace "cars" in the string with "balloons"! input.replace("cars", "balloons") }
strings4
// strings4.rs // Ok, here are a bunch of values-- some are `String`s, some are `&str`s. Your // task is to call one of these two functions on each value depending on what // you think each value is. That is, add either `string_slice` or `string` // before the parentheses on each line. If you're right, it will compile! // No hints this time! // I AM NOT DONE fn string_slice(arg: &str) { println!("{}", arg); } fn string(arg: String) { println!("{}", arg); } fn main() { ???("blue"); ???("red".to_string()); ???(String::from("hi")); ???("rust is fun!".to_owned()); ???("nice weather".into()); ???(format!("Interpolation {}", "Station")); ???(&String::from("abc")[0..1]); ???(" hello there ".trim()); ???("Happy Monday!".to_string().replace("Mon", "Tues")); ???("mY sHiFt KeY iS sTiCkY".to_lowercase()); }
solution: distinguish String and &str
fn main() { string_slice("blue"); string("red".to_string()); string(String::from("hi")); string("rust is fun!".to_owned()); string("nice weather".into()); string(format!("Interpolation {}", "Station")); string_slice(&String::from("abc")[0..1]); string_slice(" hello there ".trim()); string("Happy Monday!".to_string().replace("Mon", "Tues")); string("mY sHiFt KeY iS sTiCkY".to_lowercase()); }