让我们首先引用所有相关部分那一页(强调我的):
- 如果可以从周围的程序上下文唯一确定整数类型,则表达式具有该类型。
- 如果程序上下文对类型约束不足,则默认为带符号的 32 位整数
i32
.
-
如果程序上下文过度限制类型,它被认为是静态类型错误。
现在,由于动词“约束”的使用方式,此描述可能会产生误导。人们通常熟悉受特征约束的泛型类型,但引用可能不应该以这种方式解释。类型欠约束和过度约束是指对类型施加额外要求的情况,这些要求必须通过类型推断来考虑,这种情况在调用该类型的方法时发生。
所以不,它不适用于任何形式的约束超过一个类型。这是一个反例。
fn is_signed(x: impl num_traits::Signed) {
let _ = x.abs(); // can call abs thanks to Signed trait
}
fn main() {
is_signed(-5);
}
这段代码(操场)可能看起来“约束”-5
要求对号码进行签名,并且由于我们已经实现了Signed
对于多个整数类型,这应该是不明确的。但实际上它确实可以编译从 Rust 1.63.0 开始。
另一个特殊的例子。
trait Foo {}
impl Foo for u8 {}
impl Foo for u16 {}
fn foo(_: impl Foo) {}
fn main() {
foo(5);
}
这段代码(操场) 无法编译,但原因并非您所期望的:
error[E0277]: the trait bound `i32: Foo` is not satisfied
--> src/main.rs:9:5
|
9 | foo(5);
| ^^^ the trait `Foo` is not implemented for `i32`
|
= help: the following other types implement trait `Foo`:
u16
u8
note: required by a bound in `foo`
--> src/main.rs:6:16
|
6 | fn foo(_: impl Foo) {}
| ^^^ required by this bound in `foo`
据称,整数的类型推断机制采用了默认类型i32
,即使唯一可能的实现是u8
and u16
。无论如何,这将是另一个模棱两可的情况。
然而,当人们试图这样做时,情况就明显不同了。调用一个方法直接关联到一个类型,如(-100).abs()
。从调用该方法的那一刻起abs
,甚至存在多个整数类型,编译器将整数视为具有过度约束的类型,并且与该推理一致,发生了静态类型错误。编译器对此提供了不同的解释,具体体现为错误E0689.
对不明确的数字类型调用了方法。
无论如何,该代码无法编译的真正原因是编译器无法识别该特定情况下整数的类型,并且没有将整数类型默认为i32
。 Rust 参考不是该语言的标准参考,可能不完整或包含过时的信息。除了过度约束和约束不足的误导性概念之外,参考文献中的描述与撰写本文时编译器的行为相匹配。此时,我们很可能正在处理另一个编译器的细微差别。
也可以看看:
- Rust 中默认的整数类型是什么?
- Rust 中的文字整数值有特定类型吗?