2014-10-10 99 views
2

我試圖跟隨guide,而且我編譯如下代碼:爲什麼random()結果不具有推斷的類型?

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經驗暗示它應該)。

不完全確定這是一個錯誤,因此是一個問題。

一些額外的信息:在Ubuntu 14.04 64

➜ guess git:(master) ✗ rustc --version 
rustc 0.12.0-nightly (63fe80e1f 2014-10-08 23:42:39 +0000) 

上運行。

更新:我注意到這個錯誤是打算髮生的(該指南告訴稍後修復它的方法)。然而,爲什麼編譯器不能推斷該類型的原始問題仍然適用。

+4

這非常有趣...請注意,如果您交換參數的順序(即'100i%rand :: random()'),它會正確推斷類型。我對這種行爲也很好奇 – aochagavia 2014-10-10 13:55:51

回答

2

那麼,爲什麼編譯器無法推斷出類型的答案很簡單。這是Rem定義:

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

注意,它有兩個類型參數,RHSResult。每個性狀還具有暗示的類型參數Self,它指定了實現特徵的類型。這是Rem實施int的樣子:

impl Rem<int, int> for int { ... } 

所以在這裏Self = intRHS = intResult = int。但是特質是開放的,也就是說,你可以實現任何類型的外國特質,你可以爲任何外國類型實現你自己的特質。沒有人能阻止你添加一個實現這樣一個(Self = XRHS = intResult = 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實施Rem<int, int>會很好。因爲導入一個類型也會導入該類型的所有trait實現,然後BAM,您的程序突然停止編譯。

這可能是好的,如果它是你的程序。畢竟,你總是可以注意到這樣的編譯錯誤並相應地糾正它。但是,假設這不是發生在您的程序中,而是發生在您依賴的庫中。例如,如果使用libyXlibx,然後libx筆者決定將違規的特質實施X,然後liby突然停止編譯並沒有什麼可以做。這意味着,例如,您將無法輕鬆修改庫版本。

+0

但是,爲什麼不能選擇'int'專業化,當沒有外部特徵實現?所有它必須考慮的是內置的特質實現,其中只有一個匹配。 – 2014-10-10 18:23:46

+0

因爲這會讓你的程序非常脆弱。想象一下,你從另一個庫中導入某種類型。一切都很好,你可以在模塊的完全不相關的部分使用它。然後上游作者決定爲這種類型實施'Rem '是個好主意。因爲導入類型也意味着導入該類型的所有特徵實現,所以程序會突然停止編譯。如果它是你的程序也許可以,但如果它是另一個你不能控制但又依賴的庫?僅僅禁止這種推斷是安全得多的。 – 2014-10-10 18:29:00

+0

我已經更新了答案。 – 2014-10-10 18:38:13