与“.enumerate()”不匹配的类型:预期类型“u8”,找到引用“&_”

Mismatched types with `.enumerate()`: expected type `u8`, found reference `&_`

以下代码段无法编译

use rand::Rng;

fn main() {
    let mut rng = rand::thread_rng();
    let indices_of_odd_numbers = (1..100)
        .map(|_| rng.gen::<u8>())
        .enumerate()
        .filter(|(_, &x)| x % 2 == 1)
        .map(|(i, _)| i)
        .collect::<Vec<_>>();
    println!("{:?}", &indices_of_odd_numbers);
}

错误信息为

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
 --> src/main.rs:9:22
  |
9 |         .filter(|(_, &x)| x % 2 == 1)
  |                      ^^- expected due to this
  |                      |
  |                      expected `u8`, found reference
  |                      help: you can probably remove the explicit borrow: `x`
  |
  = note:   expected type `u8`
          found reference `&_`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground`

To learn more, run the command again with --verbose.

然而,当我将.filter(|(_, &x)| x % 2 == 1)替换为.filter(|(_, x)| *x % 2 == 1)时,它编译顺利。此外,一旦我摆脱了 .enumerate(),以下使用模式匹配将 x 隐含地推向 u8 的代码片段也会编译

use rand::Rng;

fn main() {
    let mut rng = rand::thread_rng();
    let odd_numbers = (1..100)
        .map(|_| rng.gen::<u8>())
        .filter(|&x| x % 2 == 1)
        .collect::<Vec<_>>();
    println!("{:?}", &odd_numbers);
}

我无法理解为什么模式匹配不适用于 .enumerate()。为什么编译器不能推断 x 应该是 u8 并在第一个片段中取消引用它?

enumerate() 创建一个元组,在你的情况下 (usize, u8)filter() 通过引用发送 IteratorItem,所以 &(usize, u8) 不是 (&usize, &u8)。所以 |(_, &x)| 没有意义,因为你试图取消引用 u8 的编译器。你可以做的是 |&(_, x)| 但编译器又一次足够聪明,建议简单地删除 &x& 并且你的原始文件会编译。

.filter(|(_, x)| *x % 2 == 1)比较复杂,|(_, x)|可以写成|(_, ref x)|&x的倒数,意思是参考x。所以在这里编译器自动添加 ref 关键字,然后你只需取消引用 x 即可。它更明确但不需要。

有关 RFC 2005 and binding modes

的更多信息