如何在Rust中连接两个切片?

38

我想从一个向量中取出前x个和最后x个元素并将它们连接起来。我有以下代码:

fn main() {
    let v = (0u64 .. 10).collect::<Vec<_>>();
    let l = v.len();
    vec![v.iter().take(3), v.iter().skip(l-3)];
}

这让我产生了错误

error[E0308]: mismatched types
 --> <anon>:4:28
  |
4 |     vec![v.iter().take(3), v.iter().skip(l-3)];
  |                            ^^^^^^^^^^^^^^^^^^ expected struct `std::iter::Take`, found struct `std::iter::Skip`
<anon>:4:5: 4:48 note: in this expansion of vec! (defined in <std macros>)
  |
  = note: expected type `std::iter::Take<std::slice::Iter<'_, u64>>`
  = note:    found type `std::iter::Skip<std::slice::Iter<'_, u64>>`

我该如何在 Rust 1.12 中获取我的 vec,它包含 1, 2, 3, 8, 9, 10

3个回答

62

只需在切片的切片上使用.concat()

fn main() {
    let v = (0u64 .. 10).collect::<Vec<_>>();
    let l = v.len();
    let first_and_last = [&v[..3], &v[l - 3..]].concat();
    println!("{:?}", first_and_last);
    // The output is `[0, 1, 2, 7, 8, 9]`
}

这将创建一个新的向量,并且可以处理任意数量的切片。

(Playground链接)


1
不错,但似乎需要夜间版本。 - Rawler
6
现今使用 Rust 1.62.1 完全正常。 - MEMark

22

首先,你的初始序列定义是错误的。你想要的输出是1, 2, 3, 8, 9, 10,因此它应该如下所示:

    let v = (1u64 .. 11).collect::<Vec<_>>();

接下来,你说你想要连接切片,那么让我们实际使用切片:

    let head = &v[..3];
    let tail = &v[l-3..];

现在,取决于你喜欢哪种方法。你可以将这些切片转换为迭代器,链接它们,然后收集...

    let v2: Vec<_> = head.iter().chain(tail.iter()).collect();

...或者创建一个向量并直接使用切片扩展它...

    let mut v3 = vec![];
    v3.extend_from_slice(head);
    v3.extend_from_slice(tail);

...或者使用更通用的迭代器进行扩展(在未来,这些通用迭代器将变得与特化迭代器等效,但我认为目前还不够高效...

    let mut v4: Vec<u64> = vec![];
    v4.extend(head);
    v4.extend(tail);

...或者您可以在循环中使用 Vec::with_capacitypush,或者使用链式迭代器的方法,但是使用 extend 会更好... 不过我必须在 某个 点停下。

完整示例代码:

fn main() {
    let v = (1u64 .. 11).collect::<Vec<_>>();
    let l = v.len();

    let head = &v[..3];
    let tail = &v[l-3..];

    println!("head: {:?}", head);
    println!("tail: {:?}", tail);

    let v2: Vec<_> = head.iter().chain(tail.iter()).collect();
    println!("v2: {:?}", v2);

    let mut v3 = vec![];
    v3.extend_from_slice(head);
    v3.extend_from_slice(tail);
    println!("v3: {:?}", v3);

    // Explicit type to help inference.
    let mut v4: Vec<u64> = vec![];
    v4.extend(head);
    v4.extend(tail);
    println!("v4: {:?}", v4);
}

2
extend() 应该很快被专门化为 extend_from_slice();它在几天前已经合并:Specialize Vec::extend to Vec::extend_from_slice - ljedrz
稳定版本还有大约9周左右才发布?就像我说的,现在还不是时候。 - DK.
2
让v = (1u64 .. 11).collect::<Vec<_>>(); 噢。 让v: Vec<u64> = (1..11).collect(); 耶! - Shepmaster
1
是的,只是让您知道,如果您还没有看到,它已经合并了。 - ljedrz

8
你应该使用collect()方法来收集take()extend()的结果,并将它们与skip()collect()结果进行合并:
let mut p1 = v.iter().take(3).collect::<Vec<_>>();
let p2 = v.iter().skip(l-3);

p1.extend(p2);

println!("{:?}", p1);

编辑: 如Neikos所说,您甚至不需要收集skip()的结果,因为extend()接受实现IntoIterator的参数(而Skip是一个Iterator)。

编辑2: 但您的数字有些错误;为了获得1, 2, 3, 8, 9, 10,您应将v声明如下:

let v = (1u64 .. 11).collect::<Vec<_>>();

考虑到 Range 左闭右开的特性。


谢谢。"<_>" 这个符号是否意味着“请推断类型”? - The Unfun Cat
4
你不需要收集“Skip”,因为“extend”可以接受一个迭代器。 - Neikos
1
@TheUnfunCat 是的,_ 是一个类型占位符。 - Neikos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接