我试图关注guide,并正在编译以下代码:
use std::rand;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random() % 100i) + 1i;
println!("The secret number is: {}", secret_number);
}
但是,我收到以下错误:
➜ guess git:(master) ✗ cargo run
Compiling guess v0.0.1 (file:///home/mkpankov/rust/guide/guess)
/home/mkpankov/rust/guide/guess/src/main.rs:6:26: 6:40 error: the type of this value must be known in this context
/home/mkpankov/rust/guide/guess/src/main.rs:6 let secret_number = (rand::random() % 100i) + 1i;
^~~~~~~~~~~~~~
error: aborting due to previous error
Could not compile `guess`.
To learn more, run the command again with --verbose.
我查看了%
的定义,结果显示它使用了Rem
trait。并且特征仅在相同类型的操作数上定义运算符。
现在,我使用100i
作为第二个操作数,根据reference,它应该是int
。
那么,为什么编译器能够推断random()
所请求的正确类型,正如手册所暗示的那样? (我的Haskell经验暗示它应该)。
不完全确定它是一个错误,因此问题。
其他一些信息:
➜ guess git:(master) ✗ rustc --version
rustc 0.12.0-nightly (63fe80e1f 2014-10-08 23:42:39 +0000)
在Ubuntu 14.04 x64上运行。
更新:我注意到这个错误是打算发生的(指南告诉以后修复它的方法)。但是,编译器推断出类型原因的原始问题仍然适用。
答案 0 :(得分:2)
嗯,编译器无法推断出类型的答案很简单。这是Rem
定义:
pub trait Rem<RHS, Result> {
fn rem(&self, rhs: &RHS) -> Result;
}
请注意,它需要两个类型参数RHS
和Result
。每个特征还具有名为Self
的隐式类型参数,该参数指定实现特征的类型。这就是Rem
的{{1}}实现方式:
int
所以impl Rem<int, int> for int { ... }
,Self = int
和RHS = int
。但是特征是开放的,也就是说,你可以为你拥有的任何类型实现外来特征,你可以为任何外来类型实现自己的特征。没有人可以阻止您添加类似这样的实现(Result = int
,Self = X
,RHS = int
):
Result = int
现在struct X;
impl Rem<int, int> for X {
fn rem(&self, arg: &int) -> int { *arg }
}
调用不明确:类型检查器应该选择rand::random()
还是rand::random::<X>()
?
请注意,理论上,类型检查器可以决定使用在这种情况下适用的唯一类型。但是,这会导致程序非常脆弱。假设是这种情况,原始程序正常编译。在同一模块中,但在不相关的部分中,您使用其他类型,例如rand::random::<int>()
,它是从另一个库导入的。然后,这个图书馆的作者突然决定,X
实施X
会很好。因为导入类型也会导入该类型的所有特征实现,然后BAM,您的程序突然停止编译。
如果是你的程序可能没问题。毕竟,您始终可以注意到此类编译错误并相应地进行更正。但是,假设这不是在您的程序中,而是在您依赖的库中。例如,如果Rem<int, int>
使用liby
中的X
,然后libx
作者决定为libx
添加违规特征实施,那么X
突然停止编译,你没有任何东西可以做。例如,这意味着您无法轻松修改库版本。