将Vec <string>转换为Vec&lt;&amp; str&gt;

时间:2015-10-19 14:04:18

标签: rust

我可以通过这种方式将Vec<String>转换为Vec<&str>

let mut items = Vec::<&str>::new();
for item in &another_items {
    items.push(item);
}

我想有更好的选择?

6 个答案:

答案 0 :(得分:29)

有很多方法可以做到,有些方法有缺点,有些方法对某些人来说更具可读性。

这会将s(类型为&String)取消引用至String&#34;右侧参考&#34;,然后通过{{1}取消引用}特征到Deref&#34;右侧参考&#34;然后转回str。这是编译器中常见的东西,因此我认为它是惯用的。

&str

此处let v2: Vec<&str> = v.iter().map(|s| &**s).collect(); 特征的deref函数将传递给Deref函数。它非常整洁但需要map特性或提供完整的路径。

use

这已被弃用,您不应该这样做,因为将来可以使用let v3: Vec<&str> = v.iter().map(std::ops::Deref::deref).collect(); (强制语法)来完成此操作。

|s| s: &str

这需要let v4: Vec<&str> = v.iter().map(|s| s as &str).collect(); RangeFull切片(只是整个String的一个切片)并对其进行引用。我认为这很难看。

String

这是使用强制将let v5: Vec<&str> = v.iter().map(|s| &s[..]).collect(); 转换为&String。也可以在将来用&str表达式替换。

s: &str

以下(感谢@ huon-dbaupp)使用let v6: Vec<&str> = v.iter().map(|s| { let s: &str = s; s }).collect(); 特征,该特征仅用于从拥有类型映射到其各自的借用类型。有两种方法可以使用它,而且,任何一个版本的漂亮都是完全主观的。

AsRef

let v7: Vec<&str> = v.iter().map(|s| s.as_ref()).collect();

我的底线是使用let v8: Vec<&str> = v.iter().map(AsRef::as_ref).collect(); 解决方案,因为它最明确地表达了您想要的内容。

答案 1 :(得分:8)

其他答案很简单。我只想指出,如果您尝试将Vec<&str>转换为Vec<&str>仅将其传递给以fn my_func<T: AsRef<str>>(list: &[T]) { ... } 为参数的函数,请考虑将函数签名修改为:< / p>

fn my_func(list: &Vec<&str>) { ... }

而不是:

{{1}}

正如这个问题所指出的那样:Function taking both owned and non-owned string collections。通过这种方式,两个向量都可以在不需要转换的情况下工作。

答案 2 :(得分:2)

another_items.iter().map(|item| item.deref()).collect::<Vec<&str>>()

要使用deref(),您必须使用use std::ops::Deref

添加

答案 3 :(得分:1)

这个使用collect

let strs: Vec<&str> = another_items.iter().map(|s| s as &str).collect();

答案 4 :(得分:1)

这是另一种选择:

use std::iter::FromIterator;

let v = Vec::from_iter(v.iter().map(String::as_str));

请注意,自{1.7}以来String::as_str一直稳定。

答案 5 :(得分:0)

所有答案习惯上都使用迭代器并进行收集,而不是使用循环,但是没有解释为什么这样做会更好。

在循环中,首先创建一个空向量,然后将其推入。 Rust无法保证其用于增长因子的策略,但我相信当前的策略是,每当容量超过时,向量容量就会加倍。如果原始向量的长度为20,则将是一个分配,并进行5个重新分配。

从向量进行迭代会生成一个具有“大小提示”的迭代器。在这种情况下,迭代器实现ExactSizeIterator,因此它确切知道它将返回多少个元素。 map保留了这一点,collect通过为ExactSizeIterator一次性分配足够的空间来利用这一点。

您还可以通过以下方式手动执行此操作:

let mut items = Vec::<&str>::with_capacity(another_items.len());
for item in &another_items {
    items.push(item);
}

到目前为止,堆分配和重新分配可能是整个过程中最昂贵的部分;这比不涉及新堆分配时获取引用,写入或推入向量要昂贵得多。如果将一千个元素一次性推入为该长度分配的向量比在过程中推入五个需要2个重新分配和一个分配的元素要快,这也不会令我感到惊讶。

另一个未知的优点是,将collect与方法结合使用不会将变量存储在可变变量中,如果不需要,则不要使用该变量。