如何在 Rust 中提取字符串向量的元素?

4

假设我有以下的代码:

fn extract() -> Vec<String> {
    let data = vec!["aaa".to_string(), "bbb".to_string(), "ccc".to_string()];
    vec![data[0], data[2]]
}

在实践中,我从文件中读取data

显然,这段代码无法编译,因为我从向量data中提取了字符串,导致向量处于未定义状态。但是,概念上来说,它应该可以工作,因为我之后也没有再使用data

我可以使用mem::replace,但这似乎很疯狂:

fn extract() -> Vec<String> {
    let mut data = vec!["aaa".to_string(), "bbb".to_string(), "ccc".to_string()];
    let a = mem::replace(&mut data[0], "".to_string());
    let c = mem::replace(&mut data[2], "".to_string());
    vec![a, c]
}

如何从向量中提取特定元素而不必克隆字符串?


但是,从概念上讲,它应该可以工作,因为我之后不再使用数据。如何从Vec中删除的时候知道只删除你没有删除的字符串? - Stargateur
@Stargateur它不知道,所以它无法编译。但是,未定义的数据只有在使用时才会有影响,在我的示例中它没有被使用,这就是为什么更智能的编译器应该将此代码视为有效的原因。 - Listerone
你没有理解,String有一个drop实现,因为Vec不是编译器内部的东西,所以它不能有这种程度的理解。这并不意味着你不使用数据,编译器仍然需要调用drop实现。它在Vec上执行此操作,并且Vec将在其所有元素上调用drop,Vec无法知道您移动了两个值。 - Stargateur
@Stargateur,您正在代表目前的编译器实现发言,该实现具有各种限制。我则是在代表数据安全的概念进行讲话。从未访问过的未定义数据并不是不安全的。一个更智能的编译器——即能够理解这个道理的编译器——会意识到这一点。 - Listerone
2个回答

5

Vec有特殊的方法来处理这些。比如 swap_remove, remove (警告,时间复杂度为线性),drain。例如:

fn extract() -> Vec<String> {
    let mut data = vec!["aaa".to_string(), "bbb".to_string(), "ccc".to_string()];
    // order does matter
    vec![data.swap_remove(2), data.swap_remove(0)]
}

removedrain的问题在于索引会改变。因此,如果没有追踪这些索引的更改,我就无法使用任意无序索引集提取数据。然而,在Rust中,这似乎是最好的妥协方案。谢谢。 - Listerone

1

向量中不能有“空洞”。因此,当您将某些内容移出向量时,您要么更改剩余元素的索引(使用removeswap_remove),要么用其他内容替换它。

为什么不按顺序使用向量并忽略不需要的内容?如果您需要保存一些元素以供以后使用,则可以使用data.iter().filter(...).collect()。如果您真的想避免复制任何字符串,则可以使用Rc将其包装起来,以便只复制指针。


因为我的使用情况不符合那个模型,所以我正在从成千上万个字符串的向量中选择一些关键元素。 - Listerone
1
如果你真的想避免复制任何字符串,你可以将它们包装在Rc中,这样只有指针被复制。不要这样做,Rust的移动语义不会重新分配String。 - Stargateur
OP可能无法使用move。我认为这取决于上下文。 - Hong Jiang

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