这个递归连接在 Rust 中是如何工作的

How does this recursive join work in Rust

所以我用 Rust 编写了这个递归字符串连接函数,它似乎有效,但我有点困惑为什么它有效。

fn join(separator: &str, strs: &[&str]) -> String {
    match strs.len() {
        l if l > 1    => return strs[0].to_string() + separator + &join(separator, &strs[1..]),
        l if l == 1   => return strs[0].to_string(),
        _             => return "".to_string(),
    }
}

所以我有一个包含 3 个字符串的数组和一个字符串分隔符。该函数将对 str &str 的引用作为其第一个参数,然后将对字符串数组 &[&str] 的引用作为第二个参数。

let j1 = ["one", "two", "three"];
println!("{}", join(", ", &j1));
  1. 为什么递归连接必须定义为&join(separator, &strs[1..])
  2. 为什么 &strs[1..] 必须再次取消引用?
  1. std::ops::Add<&'_ str> is implemented for String(滚动到页面底部)。 std::ops::Add<String> 不是。因此,您只能将 &'_ strs 添加到 Strings,并且只能在右侧。您必须引用对 join 的调用,因为它使用 deref 强制将 String 转换为 &str.

  2. 这个有点复杂,无法提供确切的证据,但用最简单的术语来说,切片(使用索引位置的范围)切片或数组将产生一个切片,IE,[T]。由于您不能传递裸露的 [T]s,因此您需要引用它。
    更确切的原因是:


此外,这不是编写此函数的最惯用的方式:

pub fn join(separator: &str, strs: &[&str]) -> String {
    match strs {
        [last]               => last.to_string(),
        [current, rest @ ..] => current.to_string() + separator + &join(separator, &rest),
        []                   => "".to_string(),
    }
}

Pattern matching works on slices.

  1. 为什么递归连接必须定义为&join(separator, &strs[1..])
    • + 运算符是 std::ops::Add 的语法糖。
    • String只有one Add implementationimpl<'_> Add<&'_ str> for String,这意味着你可以String + &str但不能String + String
    • 因为 join returns 一个 String,你必须从 &join(...) 的结果中得到一个 &str 才能使用 +运算符。
  2. 为什么 &strs[1..] 必须再次取消引用?(我假设你的意思是,“为什么我不能只写 strs[1..]? ")
    • 语法strs[1..]表示“strs包含的值序列从索引1到末尾”。
    • 这个序列的长度,因此它的大小,在编译时是未知的,所以它不能放在堆栈上(它必须放在堆栈上才能用作函数的参数)。
    • 您不是将值放在堆栈上,而是取对具有已知大小的值的引用。 (Rust 将此引用编译为“胖指针”,它由指向切片内存的指针和跟踪切片的长度值组成。)