[英]Using str and String interchangably
假設我正在嘗試使用&str
在Rust中做一個花哨的零拷貝解析器,但有時我需要修改文本(例如實現變量替換)。 我真的想做這樣的事情:
fn main() {
let mut v: Vec<&str> = "Hello there $world!".split_whitespace().collect();
for t in v.iter_mut() {
if (t.contains("$world")) {
*t = &t.replace("$world", "Earth");
}
}
println!("{:?}", &v);
}
但是當然t.replace()
返回的String
不夠長。 這有什么好辦法嗎? 也許有一種類型意味着“理想情況下是一個&str
但必要時是一個String
”? 或者也許有一種方法可以使用生命周期注釋告訴編譯器返回的String
應該保持活動直到main()
結束(或者與v
具有相同的生命周期)?
Rust完全以Cow
(Clone On Write)類型的形式提供。
use std::borrow::Cow;
fn main() {
let mut v: Vec<_> = "Hello there $world!".split_whitespace()
.map(|s| Cow::Borrowed(s))
.collect();
for t in v.iter_mut() {
if t.contains("$world") {
*t.to_mut() = t.replace("$world", "Earth");
}
}
println!("{:?}", &v);
}
正如@sellibitze正確指出的那樣, to_mut()
創建一個新的String
,它導致堆分配存儲先前借用的值。 如果你確定你只是借用了字符串,那么你可以使用
*t = Cow::Owned(t.replace("$world", "Earth"));
如果Vec包含Cow::Owned
元素,這仍然會丟棄分配。 您可以使用以下非常脆弱和不安全的代碼(它確實直接基於字節的UTF-8字符串操作,並且依賴於替換恰好是完全相同的字節數。)在for循環中。
let mut last_pos = 0; // so we don't start at the beginning every time
while let Some(pos) = t[last_pos..].find("$world") {
let p = pos + last_pos; // find always starts at last_pos
last_pos = pos + 5;
unsafe {
let s = t.to_mut().as_mut_vec(); // operating on Vec is easier
s.remove(p); // remove $ sign
for (c, sc) in "Earth".bytes().zip(&mut s[p..]) {
*sc = c;
}
}
}
請注意,這是根據“$ world” - >“Earth”映射精確定制的。 任何其他映射都需要在不安全的代碼中仔細考慮。
std::borrow::Cow
,專門用作Cow<'a, str>
,其中'a
是被解析字符串的生命周期。
use std::borrow::Cow;
fn main() {
let mut v: Vec<Cow<'static, str>> = vec![];
v.push("oh hai".into());
v.push(format!("there, {}.", "Mark").into());
println!("{:?}", v);
}
生產:
["oh hai", "there, Mark."]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.