What is the Rust equivalent of JavaScript's spread operator for arrays?
Asked Answered
S

3

21

In JavaScript, there is an operator called the spread operator that allows you to combine arrays very concisely.

let x = [3, 4];
let y = [5, ...x]; // y is [5, 3, 4]

Is there a way to do something like this in Rust?

Sfax answered 9/2, 2019 at 15:4 Comment(0)
M
13

If you just need y to be iterable, you can do:

let x = [3,4];
let y = [5].iter().chain(&x);

If you need it to be indexable, then you'll want to collect it into a vector.

let y: Vec<_> = [5].iter().chain(&x).map(|&x|x).collect();
Monolatry answered 9/2, 2019 at 18:0 Comment(5)
This works. Are there any significant performance implications in doing it this way?Sfax
@laptou: I doubt it. But you can compare the output assembly here: play.rust-lang.org/…Monolatry
@BenjaminLindley they defenitely will be since array is created on stack, and Vec is a heap-allocated structure.Cottonmouth
@AlexZhukovskiy: What are you comparing it to? I assumed we were comparing it to Ijedrz solution, which also uses a vector. Do you have a method that doesn't?Monolatry
I was comparing with manual implementation. It could be written as method then const generics gets stabilized.Cottonmouth
P
8

Rust's arrays have a fixed length, so there is no way of just combining them together; the usual way to achieve this result would be to have a mutable vector and to extend it with a slice:

fn main() {
    let x = [3, 4];
    let mut y = vec![5];
    y.extend_from_slice(&x);

    println!("{:?}", y); // [5, 3, 4]
}
Prepense answered 9/2, 2019 at 15:11 Comment(7)
So there is no concise way to: append x or &x[..] to the vector in the same line as vec![5], then do something with the result before assigning to y?Sfax
@Sfax references alone can only point to an existing value (for slices, this would be a contiguous section of values [T]), so no new values can be appended through a slice. Dynamic manipulation of sequences is usually performed with vectors, so that they may own that memory.Churchly
@Sfax as far as I remember there was once a suggestion to implement Add between Vec<T> and &[T], as it is already possible with String and &[str], but it was rejected.Prepense
@Churchly I understand, but since these are primitive values that implement Copy (in my specific use case, I am trying to concatenate a Vec<u8> with [u8; 2] in a single line) I was hoping there might be a shortcut.Sfax
@Sfax yep, found it: Implement Add for Vec.Prepense
@Sfax Indeed, appending values to an existing vector is possible, although there is currently no standard syntax for doing that in a single line. Extend is a suitable trait to use here once you already built a vector somewhere.Churchly
With that said, Rust arrays having a fixed length would not be an impediment to array spreading as part of the language's syntax, so long as the inputs and outputs were also arrays. I wouldn't be surprised if someone already proposed such a syntax into an RFC or just built a macro to achieve a similar effect.Churchly
K
6

You can build a Vec from as many pieces as you want using [T]::concat:

let x = [3, 4];
let y = [&[5], &x[..]].concat();
// gives vec![5, 3, 4]
Kulsrud answered 5/11, 2022 at 7:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.