Problem overview
The loop is supposed to print a message about every language in the languages vector. The expected output is:
I think Python is cool!
I think Java is cool!
I think JavaScript is cool!
The code in the editor compiles and runs, but prints the same line three times:
I think language is cool!
I think language is cool!
I think language is cool!
This is the starting code:
let languages = vec!["Python", "Java", "JavaScript"];
for language in &languages {
println!("I think language is cool!");
}
Unlike many bugs, this one produces no error. The loop works: the body runs three times, once per language. What it prints is wrong.
What goes wrong
Everything between the double quotes of a string literal is plain text. The word language inside "I think language is cool!" is just the letters l-a-n-g-u-a-g-e, not the loop variable that happens to share the name. Rust doesn't look inside a string literal for variable names. So each pass prints identical text, and the loop variable is never read.
This is a common point of confusion: a name in code refers to a variable, and the same name in quotes refers to nothing. The loop variable language holds "Python" on the first pass, "Java" on the second and "JavaScript" on the third. The message has to be told to use it.
The fix
Put a {} placeholder in the format string where the language should appear, and pass the loop variable as the next argument. println! replaces each {} with the next argument after the format string.
The message in the quotes now has a gap, and the loop variable fills it on every pass. The reference solution is:
let languages = vec!["Python", "Java", "JavaScript"];
for language in &languages {
println!("I think {} is cool!", language);
}
Tracing the three passes: language is "Python", so the line is I think Python is cool!. Then it is "Java", then "JavaScript". The output matches the expected one exactly.
Language details worth knowing
- Rust does not build strings by writing the variable inside the quotes, and it does not let you join a literal and a
&strwith+. Placeholders are the standard way. - The arguments fill the placeholders in order. With two placeholders, the first argument goes into the first
{}and the second into the second. - Rust also accepts a variable name inside the braces, as in
println!("I think {language} is cool!");. That form prints the same text. The lesson uses the explicit argument form, and both are correct. - A
{}with no argument, or an argument with no{}, is a compile error, becauseprintln!checks the format string against its arguments when the program is compiled.
Edge cases and common mistakes
- Writing
{language}only works with a plain variable name. For something likelanguages[0]or a method call, pass it as an argument instead. - Putting the variable inside the quotes without braces, which is the bug in this lesson. Nothing warns you, because the text is valid; only the output tells you.
- Printing the vector instead of the loop variable.
{}can't display aVec, and the compiler reports it.
Testing
Run the fixed code and compare the three lines against the expected output. To be sure the loop variable is really used, change "Java" in the vector to "Rust" and run again: the second line should become I think Rust is cool!, with no change to the loop. If a line stays the same after you edit the vector, the message is not reading the variable.
