2015-07-06 18 views
7

想我試圖做魯斯特使用&str看中零拷貝分析器,但有時我需要修改的文本(例如實現變量替換)。我真的很想做這樣的事情:使用STR和字符串互換

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); 
} 

當然但String通過t.replace()返回不活足夠長的時間。有沒有一個很好的解決方法?也許有一種類型意味着「理想的&str,但如果有必要String」?或者,也許還有用一生的註解告訴返回String應保持活着,直到main()末編譯器(或具有相同的壽命爲v)的方法嗎?

回答

9

鏽病正是你想要的Cow(克隆上寫)的形式,什麼類型。

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」映射精確定製的。任何其他映射都需要在不安全的代碼中仔細考慮。 (

+2

'to_mut'這裏只創建一個不必要的'String'值(涉及堆內存分配)立即被覆蓋(包括釋放),我會把這行改爲'* t = Cow :: Owned(t.replace(「$ world」,「Earth」));'以避免這種開銷 – sellibitze

+1

你最後一個例子可能除了「仔細考慮」之外,還應該有更多的警告,它會直接對基於字節的UTF-8字符串進行操作,並且依賴於替換恰好相同的字節數,這絕對是一種優化,但不是 – Shepmaster

+0

增加了更多的警告和一些粗體文本,我想知道是否有一個PR爲'Stri'添加'替換(&mut self,needle,value)'函數ng'結構將被接受 –

8

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."] 
+0

60秒太晚了:( –

+0

@ker:我在提交後10秒左右失去了電源;只是幾乎沒有成功:) D –

相關問題