为什么random()结果没有推断出类型?

时间:2014-10-10 12:03:01

标签: rust

我试图关注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上运行。

更新:我注意到这个错误是打算发生的(指南告诉以后修复它的方法)。但是,编译器推断出类型原因的原始问题仍然适用。

1 个答案:

答案 0 :(得分:2)

嗯,编译器无法推断出类型的答案很简单。这是Rem定义:

pub trait Rem<RHS, Result> {
    fn rem(&self, rhs: &RHS) -> Result;
}

请注意,它需要两个类型参数RHSResult。每个特征还具有名为Self的隐式类型参数,该参数指定实现特征的类型。这就是Rem的{​​{1}}实现方式:

int

所以impl Rem<int, int> for int { ... } Self = intRHS = int。但是特征是开放的,也就是说,你可以为你拥有的任何类型实现外来特征,你可以为任何外来类型实现自己的特征。没有人可以阻止您添加类似这样的实现(Result = intSelf = XRHS = 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突然停止编译,没有任何东西可以做。例如,这意味着您无法轻松修改库版本。