【问题标题】:Mismatched types with `.enumerate()`: expected type `u8`, found reference `&_`与 `.enumerate()` 不匹配的类型:预期类型 `u8`,找到参考 `&_`
【发布时间】:2021-10-10 14:30:31
【问题描述】:

下面的sn-p不能编译

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(|(_, &amp;x)| x % 2 == 1) 替换为.filter(|(_, x)| *x % 2 == 1) 时,它可以顺利编译。此外,一旦我摆脱了.enumerate(),以下使用模式匹配将x 隐式遵从u8 的sn-p 也会编译

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 并在第一个 sn-p 中取消引用它?

【问题讨论】:

  • rand 生成器不产生引用,而是产生 u8。元组的取消引用是自动的。没有理由使用 &,也没有使用 *(即使在第二个 sn-p 中)。
  • @Stargateur 好的,我明白了...但是为什么.filter(|(_, x)| *x % 2 == 1) 有效?模式匹配如何将 &amp;(usize, u8) 类型的内容应用到 (_, x)

标签: types rust pattern-matching type-inference type-mismatch


【解决方案1】:

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

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

更多关于RFC 2005binding modes的信息

【讨论】:

  • 在哪里可以阅读更多关于 Rust 模式匹配规则的信息? Rust 可以在执行模式匹配之前将|(_, x)| 隐式转换为|&amp;(_, x)|,这有点令人震惊。我很高兴使用这样一个聪明的编译器,但聪明也让我们更难理解它的行为。
  • @nalzok Rust 可以隐式转换有点令人震惊...... - 这个特定的功能被称为match ergonomics,甚至有点争议。不过,它被认为是一场净赢,因为它使模式匹配选项不像 PITA,特别是对于初学者而言。
  • @nalzok 通常你也没有,在你的情况下,编译器会告诉你什么是正确的代码,只需简单地编写代码并让编译器完成工作,我再也没有写过ref,因为3年。我添加了一个链接
猜你喜欢
  • 1970-01-01
  • 2021-08-05
  • 2016-07-13
  • 1970-01-01
  • 2018-09-02
  • 2016-04-22
  • 2020-11-29
  • 2015-12-13
  • 2016-09-18
相关资源
最近更新 更多