The difference is the quotes
Rust draws a hard line between text and numbers. The same digits mean different things depending on whether quotes surround them:
15without quotes is an integer. By default Rust gives it the typei32."15"with double quotes is text, a string literal of type&str. It happens to contain the characters1and5, but it is not the number fifteen.
Strings and numbers are stored differently and support different operations. You can add, subtract and compare numbers by value. A string is a sequence of characters, and its operations are things like measuring its length or joining it with another string.
let text = "15";
let number = 15;
println!("{}", text.len()); // 2: two characters
println!("{}", number + 1); // 16: arithmetic
This prints 2 and then 16.
Why Rust refuses to mix them
Rust never turns one into the other behind your back. Adding a string and a number is a compile error, in whichever order you write it:
let a = "15";
let b = 1;
println!("{}", a + b);
The compiler rejects this with error[E0369]: cannot add `{integer}` to `&str`. With the operands swapped (15 + "1"), the message is error[E0277]: cannot add `&str` to `{integer}`. Either way, the program isn't built and nothing runs.
That is a feature. If Rust guessed, "15" + 1 could mean 16 or "151", and a bug like that could hide for a long time. Instead, you say what you mean: convert the string to a number to calculate, or the number to a string to join text.
Converting between the two
A conversion is always written out. Two common ones:
let text = "15";
let n: i32 = text.parse().unwrap();
println!("{}", n + 1);
let digits = 15.to_string();
println!("{}{}", digits, "1");
The first part prints 16. The second prints 151, two pieces of text placed side by side. A string-to-number conversion with parse() can fail, because the text might not be a number, so it returns a Result. Here unwrap() takes the number out, and it would panic if the text were something like "abc". You'll meet parse again in later lessons.
The type annotation is a promise
In the lesson's exercise, every variable has its type written after the name:
let age: i32 = "29";
let phone: &str = 2025550153;
The annotation after the colon is a promise about what the variable holds, and Rust checks the value against it. Both lines break the promise, so the compiler reports error[E0308]: mismatched types for each. The first says expected `i32`, found `&str`, and the second says expected `&str`, found integer. The compiler lists both errors together.
Solving the exercise
- Fix
age. An age is a quantity you might add to or compare, so it should be a number. Remove the quotes:29. - Fix
phone. The annotation says&str, so the value needs quotes:"2025550153".
let age: i32 = 29;
let phone: &str = "2025550153";
A phone number looks numeric, but nobody adds two phone numbers or halves one. What matters is the exact sequence of digits, so text is the better fit. This also protects a number such as 007: stored as a number, the leading zeros disappear and it prints as 7, while the string "007" keeps all three characters. Phone numbers, postal codes and ID numbers are usually best kept as text.
A quick way to decide
Ask whether you will calculate with the value. If yes (an age, a price, a count), use a number type. If you will only display it, compare it exactly or join it with other text (a name, a phone number, a code), use a string.
Key takeaways
- Quotes make the difference:
15is a number,"15"is text. - Rust does not convert between them automatically. Mixing them in an operation is a compile error, and so is putting the wrong kind of value in an annotated variable.
- Convert on purpose with
parse()for string to number andto_string()for number to string. - Use numbers for values you calculate with and strings for identifiers.
