I would like a nice function to create a new vector, and to communicate that the argument vectors are no longer relevant and should be destroyed, take ownership of them. I don't particularly want to have to make either of the arguments mutable (to use append
, extend
, or push_all
and thus change the calling signature). Code (playpen link):
fn main () {
let arg1 = vec![1, 2, 3];
let arg2 = vec![4, 5, 6];
let desired = consume_and_concat(arg1, arg2);
assert_eq!(desired, vec![1, 2, 3, 4, 5, 6]);
}
fn consume_and_concat(vec1: Vec<i32>, vec2: Vec<i32>) -> Vec<i32> {
// something nice here
}
I know there's no +
for Vec
s. In Ruby, I'd do vec1 + vec2
or vec1.concat(vec2)
or [vec1, vec2].flatten
. Is there something similarly elegant that I'm missing?
I think you are looking for Extend::extend
fn main() {
let mut arg1 = vec![1, 2, 3];
let arg2 = vec![4, 5, 6];
arg1.extend(arg2);
assert_eq!(arg1, vec![1, 2, 3, 4, 5, 6]);
}
Here, we are able to reuse the allocated space from arg1
, but there's nothing to be done efficiently with the space allocated via arg2
. For an example that is more specific to your original question:
fn main() {
let arg1 = vec![1, 2, 3];
let arg2 = vec![4, 5, 6];
let desired = consume_and_concat(arg1, arg2);
assert_eq!(desired, vec![1, 2, 3, 4, 5, 6]);
}
fn consume_and_concat(mut vec1: Vec<i32>, vec2: Vec<i32>) -> Vec<i32> {
vec1.extend(vec2);
vec1
}
I would like to point out that marking an argument mut
in the signature is unnecessary; it's just a shortcut.
Thus, we can achieve the desired result without modifying the signature:
fn consume_and_concat(vec1: Vec<i32>, vec2: Vec<i32>) -> Vec<i32> {
let mut vec1 = vec1;
vec1.extend(vec2);
vec1
}
And because we reuse vec1
internal buffer, it's nearly as efficient as it gets (for better efficiency, checking the capacity of both vec1
and vec2
might lead to better result).
Of course, the shortcut:
fn consume_and_concat(mut vec1: Vec<i32>, vec2: Vec<i32>) -> Vec<i32> {
vec1.extend(vec2);
vec1
}
is, well, shorter, and as you already realized, the fact that vec1
is mut
does not change the type of its argument and thus does not change how to pass arguments.
You do not need either of them to be mutable, though if one was you would save a bit on reallocation. With Rust, one of the nice things is that you don't have to say that it consumes it. You can tell that just from the function signature. Since it doesn't take a reference, that means that the function is taking ownership.
fn main() {
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];
let concatenated_vecs = consume_and_concat(vec1, vec2);
for num in concatenated_vecs {
println!("{}", num);
}
}
fn consume_and_concat(vec1: Vec<i32>, vec2: Vec<i32>) -> Vec<i32> {
let mut result : Vec<i32> = vec![];
result.extend(vec1);
result.extend(vec2);
result
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With