如何在循环中重复执行字符串替换?

时间:2018-03-31 08:40:21

标签: string replace rust ownership

我正在编写一种方法来遍历地图的(from, to)并执行多轮tmp = tmp.replace(from, to)。我仍在努力掌握Rust的所有权概念

#[macro_use]
extern crate lazy_static;

use std::collections::HashMap;

lazy_static! {
    static ref REPLACEMENTS: HashMap<&'static str, &'static str> = {
        let mut m = HashMap::new();
        m.insert("abc", "def");
        m.insert("com", "org");
        m
    };
}

fn replace_path_name(path: &str) -> &str {
    let mut tmp = path;

    for (from, to) in REPLACEMENTS.iter() {
        let a = *from;
        let b = *to;

        tmp = tmp.replace(a, b);
    }

    tmp
}

fn main() {}

这段代码让我......

error[E0308]: mismatched types
  --> src/main.rs:22:15
   |
22 |         tmp = tmp.replace(a, b);
   |               ^^^^^^^^^^^^^^^^^
   |               |
   |               expected &str, found struct `std::string::String`
   |               help: consider borrowing here: `&tmp.replace(a, b)`
   |
   = note: expected type `&str`
              found type `std::string::String`

额外的ab是我尝试了解Rust为什么fromto成为&&str

1 个答案:

答案 0 :(得分:1)

第一个问题是您的返回值:&str。您正在返回对某些内容的引用,但拥有该值的内容是什么?您不能返回对局部变量的引用。

第二个问题是str::replace的返回类型,它是String,而不是&str。这是您的错误消息的原因:您试图将String存储在只能存储&str的变量中。你不能这样做。

最简单的修复不是最有效的;只需创建一个String

fn replace_path_name(path: &str) -> String {
    let mut tmp = String::from(path);

    for (from, to) in REPLACEMENTS.iter() {
        tmp = tmp.replace(from, to);
    }

    tmp
}

在某些情况下,您还可以使用类似Cow的类型来节省一些分配:

use std::borrow::Cow;

fn replace_path_name(path: &str) -> String {
    let mut tmp = Cow::from(path);

    for (from, to) in &*REPLACEMENTS {
        tmp = tmp.replace(from, to).into();
    }

    tmp.into()
}

甚至可以返回哪个,以便在没有替换时不会发生分配:

use std::borrow::Cow;

fn replace_path_name(path: &str) -> Cow<str> {
    let mut tmp = Cow::from(path);

    for (from, to) in &*REPLACEMENTS {
        tmp = tmp.replace(from, to).into();
    }

    tmp
}

令人遗憾的是str::replace没有返回Cow<str>。如果确实如此,如果没有替换则不会进行任何分配。

另见: