为什么编译器不能解析"a as u32 <b"或类似的?

E_n*_*ate 8 syntax-error rust

以下代码似乎微不足道(Playground):

let a: u16 = 5;
let b: u32 = 10;

let c = a as u32 < b;
Run Code Online (Sandbox Code Playgroud)

然而编译器(从2017-05-30开始)失败并出现语法错误:

error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `;`
 --> src/main.rs:6:25
  |
6 |     let c = a as u32 < b;
  |        
Run Code Online (Sandbox Code Playgroud)

编译器有什么问题?

E_n*_*ate 13

注意:最新的Rust编译器现在提供了更有用的错误消息(#42578):

error: `<` is interpreted as a start of generic arguments for `u32`, not a comparison
 --> src/main.rs:6:22
  |
6 |     let c = a as u32 < b;
  |             -------- ^ -- interpreted as generic arguments
  |             |        |
  |             |        not interpreted as comparison
  |             help: try comparing the casted value: `(a as u32)`
Run Code Online (Sandbox Code Playgroud)

这是一个已知的编译器问题(#22644).简单地说,由于u32后面跟着一个类型()<,编译器试图将其解析<为类型参数列表的开头.因此,编译器期待类似的东西u32 < b >,这在语法上是有效的,即使它没有意义.但是,一个使Rust完全有效的例子是foo as Rc < fmt::Debug >,如果语法太急于<使用less-than运算符,那么这个就会失败.

当然,从技术上讲,它有很多方法:C++和C#从一开始就具有相同的模糊性,它们碰巧有一些消除这些情况的机制(例如对任意数量的令牌进行预测),尽管也是如此解析器更复杂.在Rust中包含这些机制可能会导致语法的变化(或者可能只是rustc语法包).

由于目前没有积极的讨论来解决这个问题,一个相当简单和长期的解决方案是围绕括号包围演员:

let c = (a as u32) < b;
Run Code Online (Sandbox Code Playgroud)