在開發程式的時候常常會需要產生亂數,然而,電腦並不存在「真正隨機」的亂數,它只能夠透過一些機制,利用額外的參考數值(如時間等)來模擬出看起來是隨機的亂數。



如果想要驗證電腦的亂數並不是「真正隨機」的話,可以執行幾次以下的C語言程式:

以上程式呼叫了兩次標準函式庫提供的「rand」函數來產生出兩個隨機整數。執行結果如下:

random-integer

從執行結果我們可以看到,兩次呼叫「rand」函數所得到的值的確是不一樣的,乍看之下是亂數沒錯。但是當我們多次執行這個程式時,會發現每次執行程式所產生出來的兩個隨機整數都是同樣的那兩個整數,似乎不怎麼隨機。

為了要讓「rand」函數看起來更「接近隨機」,我們通常會將時間設為亂數產生的「亂數種子」,亂數種子即為亂數產生的參考值。程式如下:

執行結果如下:

random-integer

由於每次執行程式時,程式執行到第3行的時間點都不一樣,等於每次執行程式時都使用不同的亂數種子,所以「rand」函數回傳的結果就更「接近隨機」了!

那麼,Rust程式語言要怎麼樣產生出隨機亂數呢?在先前介紹過的猜數字程式中,我們使用了「rand」這個套件來產生亂數。但由於前面提到過,「隨機的」亂數其實需要透過一些機制來模擬出來,而「rand」這個套件算是比較低階用法的套件,可以套用不同的機制來產生亂數,因此使用起來不是那麼的方便。例如,要產生範圍在1到100中(包含1和100)的隨機整數,程式需寫成以下這樣:

以上程式看起來還算簡單,傳入至「gen_range」函數中的數值型別,即為回傳數值的型別。當然也可以利用Rust的型別推論機制,讓回傳的值在被使用或是被明確定義的時候才去決定好型別。但如果我們想要產生出範圍在5到255之間(包含5和255)的隨機u8型別整數,該怎麼做呢?嘗試撰寫以下程式:

執行以上程式,會發現程式竟然panic了!這是因為我們為了要讓「gen_range」函數能夠回傳5~255的整數,而將「5」和「256」帶進它的參數,但參數的型別和回傳值的型別必須要是相同的,因此「256」會轉成u8的話會溢位,變成「0」。而「gen_range」函數的第二個參數值必須要大於第一個參數,於是程式就panic了。

當然,這個問題也不是不能解決,只是要把程式語法改成以下這樣:

先產生出「u16」型別的亂數,因為我們確定它的範圍一定在「u8」型別範圍內,因此直接再將其轉回u8。

為了能夠讓這樣的程式更好寫,可以改用「Random Integer」套件。

Random Integer

「Random Integer」是筆者開發的套件,提供了便利的函數來產生出不同型別的整數。

Crates.io

https://crates.io/crates/random-integer

Cargo.toml

random-integer = "*"

使用方法

「random-integer」這個crate底下針對不同數值型別,提供了以「random_」為開頭名稱的函數。類似「gen_range」函數的用法,「random_」函數們都能直接透過參數傳入兩個整數來限制隨機整數的範圍,但是不同的地方在於,傳入的整數即剛好為範圍的上下界,而且第二個參數值可以小於或等於第一個參數。

例如,要產生範圍在1到100中(包含1和100)的「isize」隨機整數,程式如下:

要產生範圍在5到255中(包含5和255)的「u8」隨機整數,程式如下: