如何将不可变向量连接成一行?

时间:2018-11-25 16:02:02

标签: vector rust concatenation

我有不可变的向量ab,其中的元素很容易复制,我想创建一个向量来构成这些现有向量的级联,而不更改它们(*)。

An earlier question addressed it if one of the vectors is mutable,所以一个明显的答案是首先克隆载体a,例如

let mut r = a.clone();
r.extend(&b);

但这似乎既不优雅也不高效(扩展很容易导致不必要的重新分配,对吧?)。 (corrected) best alternative I (being a Rust noob) come up with是:

fn cat(a: &Vec<i32>, b: &Vec<i32>) -> Vec<i32> {
    let mut r = Vec::<i32>::with_capacity(a.len() + b.len());
    r.extend(a);
    r.extend(b);
    r
}

由于元素的复制成本很低,因此more generic question for vectors of strings的答案应在此处应用,但是vec![a, b].concat()似乎只有在通过将向量移入向量来构造向量的情况下才有效,因为{{ 1}}产生“找不到名为vec![&a, &b].concat()的方法”。

即使不是最佳选择,对于看似简单的工作是否也只有一线?


(*)证明“不更改”有两种含义:

  • 只是不可变的,在Rust中,这意味着如果代码编译,它将看不到变量的值已更改;但该变量可能已移出,并且以后的代码或将来的代码将无法再使用它
  • 实际上是只读的,未更改该变量以获取更多或以后的代码

2 个答案:

答案 0 :(得分:2)

  

编者注:提供此答案后,OP改变了他们的问题。请参考创建此答案的version of the question

您的第一个示例实际上没有任何意义。您提到了不变性,但是由于您将向量的所有权转移给cat函数,因此它可以选择变量的可变性。在这种情况下,您最好重用其中之一的分配:

fn cat(mut a: Vec<i32>, b: Vec<i32>) -> Vec<i32> {
    a.extend(b);
    a
}
  

扩展很容易导致不必要的重新分配

从技术上讲这是可行的,但极不可能。迭代器使用方法size_hint是有原因的-允许集合尽可能精确地分配。

  

单线

a.into_iter().chain(b).collect::<Vec<_>>()

这会破坏向量ab(而不是其中的元素)的分配,并创建一个新的分配来容纳所有项目。


如果您的切片不可变,则可以使用相同的技术:

fn cat<T: Clone>(a: &[T], b: &[T]) -> Vec<T> {
    a.iter().chain(b).cloned().collect()
}

另请参阅:

答案 1 :(得分:2)

如果正确使用,

concat可以正常工作:

fn cat(a: &[i32], b: &[i32]) -> Vec<i32> {
    [a, b].concat()
}

fn main() {
    let a = vec![1, 2, 3];
    let b = vec![7, 8, 9];
    println!("{:?}", cat(&a, &b));
}