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

How to repeatedly perform string replacement in a loop?

我正在编写一种方法来循环遍历地图的 (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.

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

第二个问题是str::replace的return类型,是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()
}

甚至可以 returned 以便在不存在替换时不进行分配:

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
}

或使用 Iterator::fold 的等效功能:

use std::borrow::Cow;

fn replace_path_name(path: &str) -> Cow<str> {
    REPLACEMENTS
        .iter()
        .fold(Cow::from(path), |s, (from, to)| s.replace(from, to).into())
}

不幸的是 str::replace 没有 return Cow<str>。如果是这样,如果不进行替换,则不会进行分配。

另请参阅:

  • Is there any way to return a reference to a variable created in a function?
  • Running a number of consecutive replacements on the same string