替换Rust Vec中的部分& str

时间:2016-05-20 21:27:25

标签: rust

我写了以下代码:

use std::str::{from_utf8};

struct JSONPointer {
    segments: Vec<String>
}

fn build_json_pointer(s: Vec<String>) -> JSONPointer {
    JSONPointer { segments: s.iter().map(|x| x.replace("~1", "/").replace("~0", "~")).collect() }
}

fn main() {
    let v = vec!["foo".to_string(), "bar".to_string(), "baz~1".to_string()];
    let p = build_json_pointer(v);

    println!("Hello world! {:?}", p.segments);
}

这一切都适用于String,但理想情况下我的JSONPointer结构将包含Vec<&str>(如果仅用于学习目的)。我遇到的问题发生在map的调用中,取代了一些保留的字符串。无论我使用的转换组合如何,我总是被告知我的borrowed value does not live long enough

我理解我正在引用本地值并尝试返回它(导致可能的删除后使用错误),但我似乎无法找到一种方法来获取副本字符串。

编辑:已更新为最低可重复格式

我现在意识到,当我指的是想要一个&#34;副本&#34; (堆分配),这正是String的内容。尽管如此,还是谈到了一种更清洁的方式。

1 个答案:

答案 0 :(得分:3)

如果您担心不必要地分配字符串,可以使用Cow

use std::borrow::Cow;

struct JSONPointer<'a> {
    segments: Vec<Cow<'a, str>>,
}

fn replace_if<'a>(s: Cow<'a, str>, from: &str, to: &str) -> Cow<'a, str> {
    if s.contains(from) {
        Cow::Owned(s.replace(from, to))
    } else {
        s
    }
}

fn build_json_pointer<'a>(s: &[&'a str]) -> JSONPointer<'a> {
    let segments = s.iter().cloned()
        .map(Cow::Borrowed)
        .map(|x| replace_if(x, "~1", "/"))
        .map(|x| replace_if(x, "~0", "~"))
        .collect();

    JSONPointer { segments: segments }
}

fn main() {
    let v = vec!["foo", "bar", "baz~1"];
    let p = build_json_pointer(&v);

    println!("Hello world! {:?}", p.segments);
}

这样做的好处是,当不需要替换时,它不需要分配任何内存,但缺点是每个模式都要被搜索两次。使用像rope这样的结构可能会更有效率。

对于接受String的原始案例,您可以通过保留原始Cow而不是无条件地替换原来的String来实现类似的内容:

struct JSONPointer {
    segments: Vec<String>,
}

fn replace_if(s: String, from: &str, to: &str) -> String {
    if s.contains(from) {
        s.replace(from, to)
    } else {
        s
    }
}

fn build_json_pointer(s: &[String]) -> JSONPointer {
    let segments = s.iter().cloned()
        .map(|x| replace_if(x, "~1", "/"))
        .map(|x| replace_if(x, "~0", "~"))
        .collect();

    JSONPointer { segments: segments }
}

fn main() {
    let v = vec!["foo".to_string(), "bar".to_string(), "baz~1".to_string()];
    let p = build_json_pointer(&v);

    println!("Hello world! {:?}", p.segments);
}