Changing the case of a string
Two methods on str change the case of every character in a string: to_uppercase() and to_lowercase().
let s = "Hello World";
let upper = s.to_uppercase();
let lower = s.to_lowercase();
println!("{}", upper);
println!("{}", lower);
println!("{}", s);
HELLO WORLD
hello world
Hello World
Both methods return a new, owned String. The original is a &str that can't be modified through those methods, and as the last line shows, it keeps its original case. If you want to keep the changed version, store the return value.
Where case conversion is useful
The most common use is comparing text without caring about case. Converting both sides to the same case makes "Yes", "YES" and "yes" equal:
let answer = "YES";
if answer.to_lowercase() == "yes" {
println!("confirmed");
}
It is also used for normalising input before storing or counting it, and for formatting output such as headings.
Unicode behaviour
Rust strings are Unicode, and to_uppercase() and to_lowercase() follow Unicode rules. That means they handle letters beyond English, and a conversion can even change the length of the text. The German letter ß has no single-character uppercase form, so:
println!("{}", "straße".to_uppercase());
STRASSE
That is one reason the methods return a new String instead of editing in place: the result may need a different amount of memory.
ASCII-only alternatives
When you know the text is plain ASCII, or you want only the ASCII letters changed, there are cheaper variants:
to_ascii_uppercase()andto_ascii_lowercase()return a newStringand change only the letters A to Z.eq_ignore_ascii_case(other)compares two strings ignoring ASCII case, without building any new string:"abc".eq_ignore_ascii_case("ABC")istrue.
Comparing without allocating
Each to_lowercase() call allocates a new String. That is fine for a few comparisons. In a loop over a large amount of text, eq_ignore_ascii_case is cheaper because it compares character by character and builds nothing. The trade-off is that it only understands ASCII case rules, so "É" and "é" would be considered different by it, while to_lowercase() treats them as a matching pair.
Gotchas
- Calling the method without using the result.
word.to_uppercase();by itself builds a string and throws it away. - Mixing up types. The result is a
String, not a&str. Comparing it with a literal works (upper == "HELLO WORLD"), but passing it to a function that expects&strneeds a borrow:&upper. - Non-letters are untouched. Digits, spaces and punctuation stay as they are.
- Only the first letter. Rust has no single method for capitalising a word. To change just one character, work with
chars()on the string.
Working with single characters
The same ideas exist for one char. c.to_ascii_uppercase() returns a char. c.to_uppercase() returns an iterator, because one character can turn into several (ß becomes SS). Collect it into a String, or print it directly, since the iterator implements Display.
To test a character before converting it, use c.is_uppercase(), c.is_lowercase() or c.is_alphabetic(). Together with chars() these let you build conversions the standard library doesn't have, such as capitalising only the first letter of each word.
Case conversion also pairs well with the other string methods in this chapter. For example, text.trim().to_lowercase() removes surrounding whitespace and then lowercases the result, which gives a clean value to compare against.
Choosing a method
Use to_lowercase() for general text, particularly user-facing text that may contain non-English letters. Use the ASCII variants for identifiers, file extensions and protocol keywords, where only A to Z can occur and speed matters more than language coverage.
The exercise
The lesson has two steps.
- Declare
wordwithlet, holding"Hello World". Then declareupperand assign itword.to_uppercase(). - Declare
lowerand assign itword.to_lowercase().
let word = "Hello World";
let upper = word.to_uppercase();
let lower = word.to_lowercase();
After this, upper is "HELLO WORLD", lower is "hello world", and word is unchanged. Both calls read from word, which is possible because each method only borrows the string.
Key takeaways
to_uppercase()andto_lowercase()convert every character and return a newString.- The original string is never modified.
- They follow Unicode rules, so the result can be longer than the input.
- Use the
_ascii_variants andeq_ignore_ascii_casewhen only ASCII matters.
