rust 如何将一个Vec解构为拥有所有权的变量?

w7t8yxp5  于 2023-01-13  发布在  其他
关注(0)|答案(3)|浏览(158)

我有一个结构体

struct Foo {
    foo1: String,
    foo2: String,
    foo3: String,
    foo4: String,
    // ...
}

我想从一个向量创建一个Foo的示例。

let x = vec!["a".to_string(), "b".to_string(), "c".to_string(), "d".to_string()];
match x.as_slice() {
    &[ref a, ref b, ref c, ref d] => {
        let foo = Foo {
            foo1: a.to_string(),
            foo2: b.to_string(),
            foo3: c.to_string(),
            foo4: d.to_string(),
        };

    },
    _ => unreachable!(),
}

我必须复制字符串吗?有没有更好的方法来将向量解构为abcd以及转移所有权?
实际上,我不介意x在重构后被完全破坏,所以我希望除了切片之外,向量也能有模式匹配,现在看来我们只能重构切片。

axr492tv

axr492tv1#

我必须复制字符串吗?
如果你愿意给予重构的话,我是itertools的忠实粉丝:

use itertools::Itertools; // 0.8.2

fn main() {
    let x = vec![
        "a".to_string(),
        "b".to_string(),
        "c".to_string(),
        "d".to_string(),
    ];

    if let Some((foo1, foo2, foo3, foo4)) = x.into_iter().tuples().next() {
        let foo = Foo {
            foo1,
            foo2,
            foo3,
            foo4,
        };
    }
}

这将把向量(以及成员)的所有权转移到迭代器,然后tuples适配器将值分成一个元组,我们取其中的第一个元组并构造值。
如果不想给予整个向量的所有权,也可以使用drain

if let Some((foo1, foo2, foo3, foo4)) = x.drain(..4).tuples().next() {

有没有更好的方法来将向量分解为abcd以及转移所有权?
不,除了迭代器之外,没有任何机制可以在不创建另一个Vec(或具有相同限制的另一个类型)的情况下获得Vec的一部分的所有权。

dy1byipe

dy1byipe2#

析构切片是不稳定的,你不能移出切片,因为它只是一个借位--如果你移出了,Vec的析构函数会怎么做?
突变载体是这里要走的路:

let mut x = vec!["a".to_string(), "b".to_string(), "c".to_string(), "d".to_string()];
let foo = Foo {
    foo4: x.pop().unwrap(),
    foo3: x.pop().unwrap(),
    foo2: x.pop().unwrap(),
    foo1: x.pop().unwrap(),
};

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

playground

fivyi3re

fivyi3re3#

如果你愿意使用nightly,这是一个#![feature(box_patterns)]的一行程序:

#![feature(box_patterns)]

let x = vec!["a".to_string(), "b".to_string(), "c".to_string(), "d".to_string()];
let Ok(box [a, b, c, d]) = <Box<[String; 4]>>::try_from(x) else { unreachable!() };

稳定性说明:
请注意,这些框模式在将来可能会被更通用的“deref”模式所取代,因此很可能永远不会稳定下来。
这些是否允许移动 * 所有权 * 是未知的,因为不存在任何类型的DerefInto特性,只有DerefDerefMut * 借用 *。
然而,我希望box_patterns特性不会被删除,直到有另一种方法可以做到这一点。(或者至少,直到另一个特性可以提供相同的特性来取代它),所以你可以(大多数情况下)安全地使用这个特性,而不会在未来被锁定。在任何情况下,如果发生这种情况,你都可以使用其他答案之一来重新实现它。

相关问题