rust 如何在一行中连接不可变向量?

rnmwe5a2  于 2023-08-05  发布在  其他
关注(0)|答案(3)|浏览(82)

我有不可变的向量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()似乎只有在通过将向量移动到其中来构造向量的向量时才有效,因为vec![&a, &b].concat()产生“未找到名为concat的方法”。
对于这个看似简单的工作,是否有一个一行程序,即使它不是最佳的?

  • (*)原来“不变”有两个意思:
  • 只是不可变的,在Rust中这意味着如果代码编译,它不会看到值改变的变量;但是变量的值可能会被移出,并且将来的代码不能再使用该变量。
  • 实际上是只读的,使变量保持不变,以供将来的代码使用;这就是我要找的东西。
dfddblmv

dfddblmv1#

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));
}

字符串

bprjcwpo

bprjcwpo2#

数组可以将concat()切片为一个向量,你只需要给予编译器一个更强的提示:

let combined = [a.as_slice(), b.as_slice()].concat();

字符串
这里有一个rust playground to try it out。可以看到ab都没有被消耗,combined是一个新的向量。请注意,如果您尝试使用&简写借用,而不是指定as_slice(),则此操作将失败。

zdwk9cvp

zdwk9cvp3#

编者按:在提供了这个答案后,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的分配(而不是它们内部的元素),并创建了一个新的分配来保存所有项。
如果你有不可变的 * slice *,你可以使用同样的技术:

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


参见:

相关问题