Concatenating Strings in Rust: TOP-5 Beginner Mistakes (and How to Avoid Them)

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why Can't You Just Add Strings in Rust?

\n\n

If you switched to Rust from Python or JavaScript, the first thing that probably shocked you was trying to write "Hello, " + "world!". The compiler greets you with a red squiggly line and a mysterious error message. In the Python world, this would work instantly, but Rust is a different beast. The question "How do I concatenate strings?" on Stack Overflow has garnered hundreds of thousands of views, and this is no coincidence.

\n\n

The problem is that string concatenation in Rust is not just syntactic sugar. It's a matter of memory management, ownership, and data types. If you are a beginner, you can easily step on classic rakes: lose ownership of a string, accidentally copy gigabytes of data, or simply get confused between String and &str.

\n\n

In this article, we will break down the 5 most common mistakes that beginners make when joining strings in Rust and show you how to avoid them. You will learn when to use +, when to use format!, and when to use push_str. Let's go!

\n\n

Mistake #1: Forgetting About Ownership

\n\n

What It Looks Like

\n\n

Imagine you write this code:

\n\n
let s1 = String::from("Hello");\nlet s2 = String::from(", world!");\nlet s3 = s1 + &s2; // Error? Or not?\nprintln!("{}", s1); // Compilation error!
\n\n

You expect s1 to remain available, but the compiler says: "No, s1 has been moved."

\n\n

The Essence of the Mistake

\n\n

In Rust, the + operator for strings uses the signature fn add(self, s: &str) -> String. Note the self — this means the first string is consumed and you can no longer use it. You literally "give away" s1 to the add function, and it becomes unavailable.

\n\n

How to Fix It

\n\n

There are two ways:

\n\n
    \n
  • Clone the string (if you need the original): let s3 = s1.clone() + &s2;
  • \n
  • Change the order or use format!:
  • \n
\n\n
let s1 = String::from("Hello");\nlet s2 = String::from(", world!");\nlet s3 = format!("{}{}", s1, s2); // s1 and s2 remain available\nprintln!("{}", s1); // Works!
\n\n

Tip: If you don't plan to use s1 after concatenation, feel free to use +. It is faster than format! because it doesn't create a new buffer from scratch.

\n\n

Mistake #2: Confusion Between String and &str

\n\n

What It Looks Like

\n\n

You try to add a String with a literal:

\n\n
let s = String::from("Hello");\nlet result = s + " world"; // Works!
\n\n

But if you try the opposite:

\n\n
let s = "Hello";\nlet result = s + String::from(" world"); // Error!
\n\n

The Essence of the Mistake

\n\n

The + operator only works when the left side is a String and the right side is a &str. The literal " world" is automatically a &str, so the first example works. In the second example, s is a &str, which does not have an add method.

\n\n

How to Fix It

\n\n

Convert the &str to a String or use format!:

\n\n
let s = "Hello";\nlet result = format!("{} {}", s, "world"); // Universal way\n// Or\nlet result = s.to_string() + " world"; // to_string() creates a String
\n\n

Golden rule: String is an owned type, &str is a borrow. Concatenation always requires ownership on the left.

\n\n

Mistake #3

Blogs

Book Recommendations