为什么直接传递函数时会出现“类型不匹配”错误,但它可以与等效的闭包一起使用?

Ahm*_*hal 11 rust

为了让我的代码更简洁,我尝试通过名称直接将闭包传递map()&[&str]. map 需要迭代&&str这是可以理解的,但我的闭包只需要&str.

代码示例:

fn capitalize_first(word: &str) -> String {
    word.chars().next().unwrap().to_uppercase().to_string()
}
fn main() {
    let cap_cap = |word: &&str| -> String {
        word.chars().next().unwrap().to_uppercase().to_string()
        };
    let a = ["we", "are", "testing"];

    let b = &a; // this is where this becomes interesting.
    
    b.iter().map(|&x| capitalize_first(x)); // Works
    b.iter().map(|x| capitalize_first(x));  // Works
    
    b.iter().map(cap_cap); // That's what the compiler expects.
    
    b.iter().map(capitalize_first); // fails to compile!
}
Run Code Online (Sandbox Code Playgroud)

编译器错误:

error[E0631]: type mismatch in function arguments
  --> src/main.rs:17:18
   |
1  | fn capitalize_first(word: &str) -> String {
   | ----------------------------------------- found signature of `for<'r> fn(&'r str) -> _`
...
16 |     b.iter().map(capitalize_first); // fails to compile!
   |                  ^^^^^^^^^^^^^^^^ expected signature of `fn(&&str) -> _`
Run Code Online (Sandbox Code Playgroud)

有几个问题:

  1. 为什么这有效map(|x| capitalize_first(x))map(capitalize_first)无效?第一个案例的幕后发生了什么样的魔法?在我看来,这些应该是相同的。
  2. 是否有原因导致 Rust 无法在&&str和 之间透明地转换&str

kmd*_*eko 10

是否有原因导致 Rust 无法在&&str和 之间透明地转换&str

Rust确实透明地从 转换为&&str&str您可以在您的工作示例之一中看到它:

b.iter().map(|x| capitalize_first(x))
           // ^ x is a &&str here ^ but seems to be a &str here
Run Code Online (Sandbox Code Playgroud)

幕后发生了什么样的魔法[?]

发生的“魔法是由于类型强制,特别是Deref强制“类型强制是改变值类型的隐式操作”


为什么这有效map(|x| capitalize_first(x))map(capitalize_first)无效?

您发现,虽然 to 存在强制&&str,但to&str没有强制。可用的强制非常有限。fn(&&str)fn(&str)

最重要的是,只有特定的地方可以发生强制,但第一个案例之所以有效是因为,随着关闭,强制站点就可以在您调用的地方可用capitalize_first

b.iter().map(|x| capitalize_first(x))
                               // ^ the compiler injects code here to do the coercion 
                               //   as if you had written capitalize_first(*x)
Run Code Online (Sandbox Code Playgroud)

当您直接使用该函数时,不存在可以发生强制转换的站点。