如何用新格式化的字符串替换字符串切片的Vec中的一个元素?

Pet*_*lka 2 rust

我正在尝试替换字符串切片列表中的一行,并且无法使其有效期正确。

这是我的代码:

pub struct SomeDataType<'a> {
    pub lines: Vec<&'a str>,
    // other fields omitted
}

impl<'a> SomeDataType<'a> {
    pub fn parse(text: &str) -> Result<SomeDataType, String> {
        let lines: Vec<&str> = text.lines().collect();
        Ok(SomeDataType { lines })
    }

    // replace first occurrence, and return original value
    pub fn replace_placeholder(&mut self, real_value: &str) -> Option<String> {
        let newstr = format!("## {}", real_value);
        for line in self.lines.iter_mut() {
            if line.starts_with("## PLACEHOLDER") {
                let original: String = String::from(*line);
                *line = newstr.as_str();
                return Some(original);
            }
        }
        None
    }
}

fn main() {
    let text = r##"
Lorem ipsum
## PLACEHOLDER 1
dolor sit amet,
## PLACEHOLDER 2
consectetur adipiscing elit,
"##;

    let mut x = SomeDataType::parse(text).unwrap();
    let original = x.replace_placeholder("The Real Value");
    println!("ORIGINAL VALUE: {:?}", original); //prints: ORIGINAL VALUE: Some("## PLACEHOLDER 1")
    println!("{}", x.lines.join("\n")) //prints the text with first occurrence replaced
}
Run Code Online (Sandbox Code Playgroud)
error[E0597]: `newstr` does not live long enough
  --> src/main.rs:18:25
   |
6  | impl<'a> SomeDataType<'a> {
   |      -- lifetime `'a` defined here
...
18 |                 *line = newstr.as_str();
   |                 --------^^^^^^---------
   |                 |       |
   |                 |       borrowed value does not live long enough
   |                 assignment requires that `newstr` is borrowed for `'a`
...
23 |     }
   |     - `newstr` dropped here while still borrowed

Run Code Online (Sandbox Code Playgroud)

这一定是借用和终身的,但我不知道这是什么。

Sve*_*ach 5

Your data structure

pub struct SomeDataType<'a> {
    lines: Vec<&'a str>,
}
Run Code Online (Sandbox Code Playgroud)

stores references to string slices. Since in Rust references must always be valid, these string slices need to live longer than the instance of SomeDataType, and the lifetime of each string slice must be at least 'a.

Your function replace_placeholder() creates a new local String instance in this line:

let newstr = format!("## {}", real_value);
Run Code Online (Sandbox Code Playgroud)

This String instance only lives for the runtime of the function, since it is a local variable. To be able to store a reference to this string in self.lines, it would at least have to live for the lifetime 'a of SomeDataType, which is doesn't. This is why the compiler complains.

With your current data structure, you can't really make this work. Any string you create in replace_placeholder() will only live for the runtime of the function, unless you can pass ownership of the string to a longer-lived data structure. SomeDataType cannot take ownership, though – it only stores references.

The easiest solution is to change your data type definition to

pub struct SomeDataType {
    lines: Vec<String>,
}
Run Code Online (Sandbox Code Playgroud)

so it owns all strings. This will require you to create new String objects from the lines you parse, so you will copy all lines. This is unlikely to be a problem, but if for some reason you need to avoid this overhead, you can also use a vector of Cow<'a, str>. This data structure is able to store either a reference or an owned string.