How do I concatenate the following combinations of types:
str and str
String and str
String and String
str
and &str
are different types and for 99% of the time, you only should care about &str
. There are other questions detailing the differences between them.
When you concatenate strings, you need to allocate memory to store the result. The easiest to start with is String
and &str
:
fn main() {
let mut owned_string: String = "hello ".to_owned();
let borrowed_string: &str = "world";
owned_string.push_str(borrowed_string);
println!("{}", owned_string);
}
Here, we have an owned string that we can mutate. This is efficient as it potentially allows us to reuse the memory allocation. There's a similar case for String
and String
, as &String
can be dereferenced as &str
.
fn main() {
let mut owned_string: String = "hello ".to_owned();
let another_owned_string: String = "world".to_owned();
owned_string.push_str(&another_owned_string);
println!("{}", owned_string);
}
After this, another_owned_string
is untouched (note no mut
qualifier). There's another variant that consumes the String
but doesn't require it to be mutable. This is an implementation of the Add
trait that takes a String
as the left-hand side and a &str
as the right-hand side:
fn main() {
let owned_string: String = "hello ".to_owned();
let borrowed_string: &str = "world";
let new_owned_string = owned_string + borrowed_string;
println!("{}", new_owned_string);
}
Note that owned_string
is no longer accessible after the call to +
.
What if we wanted to produce a new string, leaving both untouched? The simplest way is to use format!
:
fn main() {
let borrowed_string: &str = "hello ";
let another_borrowed_string: &str = "world";
let together = format!("{}{}", borrowed_string, another_borrowed_string);
// After https://rust-lang.github.io/rfcs/2795-format-args-implicit-identifiers.html
// let together = format!("{borrowed_string}{another_borrowed_string}");
println!("{}", together);
}
Note that both input variables are immutable, so we know that they aren't touched. If we wanted to do the same thing for any combination of String
, we can use the fact that String
also can be formatted:
fn main() {
let owned_string: String = "hello ".to_owned();
let another_owned_string: String = "world".to_owned();
let together = format!("{}{}", owned_string, another_owned_string);
// After https://rust-lang.github.io/rfcs/2795-format-args-implicit-identifiers.html
// let together = format!("{owned_string}{another_owned_string}");
println!("{}", together);
}
You don't have to use format!
though. You can clone one string and append the other string to the new string:
fn main() {
let owned_string: String = "hello ".to_owned();
let borrowed_string: &str = "world";
let together = owned_string.clone() + borrowed_string;
println!("{}", together);
}
Note - all of the type specification I did is redundant - the compiler can infer all the types in play here. I added them simply to be clear to people new to Rust, as I expect this question to be popular with that group!
To concatenate multiple strings into a single string, separated by another character, there are a couple of ways.
The nicest I have seen is using the join
method on an array:
fn main() {
let a = "Hello";
let b = "world";
let result = [a, b].join("\n");
print!("{}", result);
}
Depending on your use case you might also prefer more control:
fn main() {
let a = "Hello";
let b = "world";
let result = format!("{}\n{}", a, b);
print!("{}", result);
}
There are some more manual ways I have seen, some avoiding one or two allocations here and there. For readability purposes I find the above two to be sufficient.
join
documented? It seems to sit halfway between an Array and a String. I searched through the array documentation and was quickly confused.
join
is actually attached to the SliceContactExt
trait. The trait is marked unstable but its methods are stable and are included in the Prelude so they're usable everywhere by default. The team appear to be well aware this trait does not need to exist and I imagine things will change in future with it.
join
is more efficient than s1.to_owned().push_str(s2)
for concatenating two str
's as it avoids the second allocation.
Simple ways to concatenate strings in Rust
There are various methods available in Rust to concatenate strings
First method (Using concat!() ):
fn main() {
println!("{}", concat!("a", "b"))
}
The output of the above code is :
ab
Second method (using push_str() and + operator):
fn main() {
let mut _a = "a".to_string();
let _b = "b".to_string();
let _c = "c".to_string();
_a.push_str(&_b);
println!("{}", _a);
println!("{}", _a + &_c);
}
The output of the above code is:
ab abc
Third method (Using format!()):
fn main() {
let mut _a = "a".to_string();
let _b = "b".to_string();
let _c = format!("{}{}", _a, _b);
println!("{}", _c);
}
The output of the above code is :
ab
Check it out and experiment with Rust playground.
concat
only works with literals, so, not super useful.
I think that concat
method and +
should be mentioned here as well:
assert_eq!(
("My".to_owned() + " " + "string"),
["My", " ", "string"].concat()
);
and there is also concat!
macro but only for literals:
let s = concat!("test", 10, 'b', true);
assert_eq!(s, "test10btrue");
+
is already mentioned in an existing answer. (This is an implementation of the Add
trait that takes a String
as the left-hand side and a &str
as the right-hand side:)
Concatenation by String Interpolation
UPDATE: As of 2021, Dec 28, this is available in Rust 1.58 Beta. You no longer need Rust Nightly build to do String Interpolation. (Leaving remainder of answer unchanged for posterity).
RFC 2795 issued 2019-10-27: Suggests support for implicit arguments to do what many people would know as "string interpolation" -- a way of embedding arguments within a string to concatenate them.
RFC: https://rust-lang.github.io/rfcs/2795-format-args-implicit-identifiers.html
Latest issue status can be found here: https://github.com/rust-lang/rust/issues/67984
At the time of this writing (2020-9-24), I believe this feature should be available in the Rust Nightly build.
This will allow you to concatenate via the following shorthand:
format_args!("hello {person}")
It is equivalent to this:
format_args!("hello {person}", person=person)
There is also the "ifmt" crate, which provides its own kind of string interpolation:
As of Rust 1.58, you can also concatenate two or more variables like this: format!("{a}{b}{c}")
. That's basically the same as format!("{}{}{}", a, b, c)
, but a bit shorter and (arguably) easier to read. Those variables can be String
, &str
(and also other non-string types for that matter). The result is a String
. See this for more.
By Default in Rust is all about MemoryManage and Owenership and Move, we dont see usually like copy or deep copy hence if you are trying to concatinate strings then left hand side should type String which is growable and should be mutable type, the right hand side can be normal string literal a.k.a type String slices
fn main (){
let mut x = String::from("Hello"); // type String
let y = "World" // type &str
println!("data printing -------> {}",x+y);
}
https://i.stack.imgur.com/h6WQI.png
fn main() {
let a = String::from("Name");
let b = "Pkgamer";
println!("{}",a+b)
}
&str
/String
?), and your answer doesn't add much over e.g. this one.
Success story sharing
Add
/+
symbol? You could cover it if you want..to_owned()
and.to_string()
has been fixed since the above comment thanks to impl specialization. They both now have the same performance when called on a&str
. Relevant commit: github.com/rust-lang/rust/pull/32586/filesString
, but then you take a reference to one (&String
) which can be coerced to a&str
. I put the entire pathString
->&String
->&str
because beginners may not even realize that you can take a reference to aString
. :-)