Caballero
Caballero

Reputation: 12131

String concatenation from vector tuple

This is as simple as it gets, yet I have no clue why it doesn't work.

fn main() {
    let vector = vec![("foo".to_string(), "bar".to_string())];
    let string = vector[0].0 + vector[0].1;
}

Error

src/main.rs:3:29: 3:40 error: mismatched types:
 expected `&str`,
    found `collections::string::String`
(expected &-ptr,
    found struct `collections::string::String`) [E0308]
src/main.rs:3   let string = vector[0].0 + vector[0].1;
                                           ^~~~~~~~~~~

So then I change it to this:

fn main() {
    let vector = vec![("foo".to_string(), "bar".to_string())];
    let string = &*vector[0].0 + &*vector[0].1;
}

Get another error

src/main.rs:3:15: 3:28 error: binary operation `+` cannot be applied to type `&str` [E0369]
src/main.rs:3   let string = &*vector[0].0 + &*vector[0].1;
                             ^~~~~~~~~~~~~
src/main.rs:3:15: 3:28 help: run `rustc --explain E0369` to see a detailed explanation
src/main.rs:3:15: 3:28 note: an implementation of `std::ops::Add` might be missing for `&str`
src/main.rs:3   let string = &*vector[0].0 + &*vector[0].1;
                             ^~~~~~~~~~~~~

I've exhausted all the combinations I could think of. What am I missing here?

Upvotes: 0

Views: 1065

Answers (1)

Vladimir Matveev
Vladimir Matveev

Reputation: 128181

This does not work because concatenation is defined only on String, and it consumes its left operand:

let s = "hello ".to_string();
let c = s + "world";
println!("{}", c);  // hello world
println!("{}", s);  // compilation error

Therefore it needs by-value access to the string, but it cannot be done with indexing on a vector - they can only return references into the vector, not values.

There are several ways to overcome this, for example, you can clone the string:

let string = vector[0].0.clone() + &vector[0].1;

Or you can use formatting:

let string = format!("{}{}", vector[0].0, vector[0].1);

Or you can take the value out of the vector with remove() or swap_remove():

let string = match vector.swap_remove(0) {
    (left, right) => left + right
};

The latter, naturally, is appropriate if it's okay for you to lose the state of the vector. If you want to do this for the whole vector, it is better to iterate it by value, consuming it in the process:

for (left, right) in vector {
    let string = left + right;
}

Upvotes: 4

Related Questions