将 Vec<String> 转换为 Rust 中的 &str 切片?
Posted
技术标签:
【中文标题】将 Vec<String> 转换为 Rust 中的 &str 切片?【英文标题】:Convert Vec<String> into a slice of &str in Rust? 【发布时间】:2017-05-01 23:17:49 【问题描述】:根据Steve Klabnik's writeup in the pre-Rust 1.0 documentation on the difference between String
and &str
,在Rust 中你应该使用&str
,除非你真的需要拥有String
的所有权。同样,除非您确实需要对 Vec
的所有权,否则建议使用对切片 (&[]
) 的引用而不是 Vec
s。
我有一个Vec<String>
,我想编写一个使用此字符串序列的函数,它不需要拥有Vec
或String
实例的所有权,该函数是否应该采用&[&str]
?如果是这样,将Vec<String>
引用到&[&str]
的最佳方法是什么?或者,这种强制是不是矫枉过正?
【问题讨论】:
【参考方案1】:您可以使用AsRef
trait 创建一个同时接受&[String]
和&[&str]
的函数:
fn test<T: AsRef<str>>(inp: &[T])
for x in inp print!(" ", x.as_ref())
println!("");
fn main()
let vref = vec!["Hello", "world!"];
let vown = vec!["May the Force".to_owned(), "be with you.".to_owned()];
test(&vref);
test(&vown);
【讨论】:
我认为这是 OP 正在寻找的答案,因为它允许在没有不必要分配的情况下使用切片。这种方法在接受AsRef<Path>
的切片时更加有用 - 您希望函数接受所有 &[&str]
、&[String]
、&[Path]
和 &[PathBuf]
,而不分配新内存。
一件可悲的事情是,如果您尝试使用Option<&[T]>
,您不能只通过None
而不指定具体类型【参考方案2】:
如果没有内存分配,这实际上是不可能的1。
从String
到&str
不仅仅是从不同的角度看待比特; String
和 &str
具有不同的内存布局,因此从一个到另一个需要创建一个新对象。这同样适用于Vec
和&[]
因此,虽然您可以从Vec<T>
转到&[T]
,从而从Vec<String>
转到&[String]
,但您不能直接从Vec<String>
转到&[&str]
。您的选择是:
&[String]
分配一个新的Vec<&str>
引用第一个Vec
,并将那个转换成&[&str]
以分配为例:
fn usage(_: &[&str])
fn main()
let owned = vec![String::new()];
let half_owned: Vec<_> = owned.iter().map(String::as_str).collect();
usage(&half_owned);
1所需的转换是不可能的,但是使用泛型和AsRef<str>
绑定,如@aSpex 的答案所示,您会得到一个稍微冗长的函数声明,并且具有您的灵活性要求。
【讨论】:
谢谢,马修。对于我现在的情况,我想我会选择&[String]
,因为我认为分配一个新的Vec<&str>
会产生额外的工作。
@DonRowe:它会产生额外的分配(O(1) 但可能很昂贵)+ 转换(O(n))。以上是关于将 Vec<String> 转换为 Rust 中的 &str 切片?的主要内容,如果未能解决你的问题,请参考以下文章
为什么使用Vec :: contains时&str不会强制转换为&String?
std::vector<cv::Vec3b> 到 cv::Mat