簡體   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