First, in Rust x += y
is not overloadable, so +=
operator won't work for anything except basic numeric types. However, even if it worked for strings, it would be equivalent to x = x + y
, like in the following:
res = res + format!("{} {}\n",i.to_string(),ch.to_string())
Even if this were allowed by the type system (it is not because String + String
"overload" is not defined in Rust), this is still not how fold()
operates. You want this:
res + &format!("{} {}\n", i, ch)
or, as a compilable example,
fn main(){
let x = "hello";
let res : String = x.chars().enumerate().fold(String::new(), |res, (i, ch)| {
res + &format!("{} {}\n", i, ch)
});
println!("{}", res);
}
When you perform a fold, you don't reassign the accumulator variable, you need to return the new value for it to be used on the next iteration, and this is exactly what res + format!(...)
do.
Note that I've removed to_string()
invocations because they are completely unnecessary - in fact, x.to_string()
is equivalent to format!("{}", x)
, so you only perform unnecessary allocations here.
Additionally, I'm taking format!()
result by reference: &format!(...)
. This is necessary because +
"overload" for strings is defined for String + &str
pair of types, so you need to convert from String
(the result of format!()
) to &str
, and this can be done simply by using &
here (because of deref coercion).
In fact, the following would be more efficient:
use std::fmt::Write;
fn main(){
let x = "hello";
let res: String = x.chars().enumerate().fold(String::new(), |mut res, (i, ch)| {
write!(&mut res, "{} {}\n", i, ch).unwrap();
res
});
println!("{}", res);
}
which could be written more idiomatically as
use std::fmt::Write;
fn main(){
let x = "hello";
let mut res = String::new();
for (i, ch) in x.chars().enumerate() {
write!(&mut res, "{} {}\n", i, ch).unwrap();
}
println!("{}", res);
}
(try it on playpen)
This way no extra allocations (i.e. new strings from format!()
) are created. We just fill the string with the new data, very similar, for example, to how StringBuilder
in Java works. use std::fmt::Write
here is needed to allow calling write!()
on &mut String
.
I would also suggest reading the chapter on strings in the official Rust book (and the book as a whole if you're new to Rust). It explains what String
and &str
are, how they are different and how to work with them efficiently.