I started programming with Rust this week and I am having a lot of problems understanding how Strings work.
Right now, I am trying to do a simple program that prints a list of players appending their order(for learning purposes only).
let res : String = pl.name.chars().enumerate().fold(String::new(),|res,(i,ch)| -> String {
res+=format!("{} {}\n",i.to_string(),ch.to_string());
});
println!("{}", res);
This is my idea, I know I could just use a for loop but the objective is to understand the different Iterator functions.
So, my problem is that the String concatenation does not work.
Compiling prueba2 v0.1.0 (file:///home/pancho111203/projects/prueba2)
src/main.rs:27:13: 27:16 error: binary assignment operation `+=` cannot be applied to types `collections::string::String` and `collections::string::String` [E0368]
src/main.rs:27 res+=format!("{} {}\n",i.to_string(),ch.to_string());
^~~
error: aborting due to previous error
Could not compile `prueba2`.
I tried using &str but it is not possible to create them from i and ch values.
First, in Rust
x += yis not overloadable, so+=operator won't work for anything except basic numeric types. However, even if it worked for strings, it would be equivalent tox = x + y, like in the following: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 howfold()operates. You want this:or, as a compilable example,
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 toformat!("{}", 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 forString + &strpair of types, so you need to convert fromString(the result offormat!()) to&str, and this can be done simply by using&here (because of deref coercion).In fact, the following would be more efficient:
which could be written more idiomatically as
(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 howStringBuilderin Java works.use std::fmt::Writehere is needed to allow callingwrite!()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
Stringand&strare, how they are different and how to work with them efficiently.