繁体   English   中英

如何转换 Vec<String> 到 Vec&lt;&amp;str&gt;?

[英]How do I convert a Vec<String> to Vec<&str>?

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

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

有更好的选择吗?

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

这将s (类型为&String )取消引用为String “右侧引用”,然后通过Deref特性将其取消引用为str “右手侧引用”,然后再转换回&str 这是在编译器中非常常见的东西,因此我认为它是惯用的。

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

在这里, deref的功能Deref性状传递给map功能。 它非常简洁,但需要use trait 或提供完整路径。

let v3: Vec<&str> = v.iter().map(std::ops::Deref::deref).collect();

这使用强制语法。

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

这需要StringRangeFull切片(只是整个String一个切片)并引用它。 在我看来这很丑陋。

let v5: Vec<&str> = v.iter().map(|s| &s[..]).collect();

这是使用强制转换将&String转换为&str 将来也可以替换为s: &str表达式。

let v6: Vec<&str> = v.iter().map(|s| { let s: &str = s; s }).collect();

以下(感谢@huon-dbaupp)使用AsRef trait,它仅存在于从拥有的类型映射到它们各自的借用类型。 有两种方法可以使用它,同样,任何一个版本的漂亮程度都是完全主观的。

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

let v8: Vec<&str> = v.iter().map(AsRef::as_ref).collect();

我的底线是使用v8解决方案,因为它最明确地表达了您想要的内容。

其他答案很简单。 我只想指出,如果您试图将Vec<String>转换为Vec<&str>只是为了将其传递Vec<&str>作为参数的函数,请考虑将函数签名修改为:

fn my_func<T: AsRef<str>>(list: &[T]) { ... }

代替:

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

正如这个问题所指出的:函数采用拥有和非拥有的字符串集合 通过这种方式,两个向量都可以简单地工作而无需转换。

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

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

所有的答案都习惯性地使用迭代器和收集而不是循环,但没有解释为什么这更好。

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

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

您也可以使用以下方法手动执行此操作:

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

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

另一个不为人知的优点是,使用带有collect的方法不会存储在不需要时不应使用的可变变量中。

这个使用collect

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

这是另一种选择:

use std::iter::FromIterator;

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

注意String::as_str从 Rust 1.7 String::as_str就稳定了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM