這是課程"做你自己的套利機器人"的輔助課。第 13 課把掃描器的熱點迴圈搬到 Rust 裡。你不需要成為 Rust 程式員,只要能讀一小段程式並執行它。
直接的辦法:繼續用 Python
第一個掃描器用 Python 沒問題。麻煩從一個函式每秒要執行數百萬次時開始:解釋器每一步都要多做工作。像 Rust 這樣的編譯型語言,在執行前一次性把程式變成機器碼,之後迴圈的每一步幾乎不花什麼。代價是要多寫一點,而且編譯器很嚴格。
一個小程式
還是上一篇預備課裡的那四個價格。保存為 r.rs:
fn mean(v: &Vec<f64>) -> f64 {
let mut sum = 0.0;
for x in v {
sum += x;
}
sum / v.len() as f64
}
fn main() {
let prices: Vec<f64> = vec![100.0, 101.5, 99.8, 102.0];
let mut best = 0.0;
for i in 0..prices.len() - 1 {
let ratio = prices[i + 1] / prices[i];
println!("step {}: ratio {:.4}", i, ratio);
if ratio > best {
best = ratio;
}
}
println!("best {:.4}, mean price {:.3}", best, mean(&prices));
}
編譯並執行:rustc -O r.rs -o r && ./r。
step 0: ratio 1.0150
step 1: ratio 0.9833
step 2: ratio 1.0220
best 1.0220, mean price 100.825
怎麼讀
fn name(...) -> type { ... }定義一個函式。最後一個不帶分號的表達式就是它的返回值:sum / v.len() as f64返回平均值。let創建變數。除非寫成let mut,否則它不能改變。所以sum和best帶了mut。Vec<f64>是一列小數(向量)。vec![...]創建它。v.len()是它的長度。for i in 0..n讓 i 從 0 迴圈到 n 減 1。for x in v遍歷每一項。&prices的意思是"把向量借給函式,不要送出去"。細節現在可以先跳過:如果編譯器抱怨所有權問題,把提示訊息給你的智慧體看。println!用來列印。{}是放值的位置,{:.4}是保留小數點後 4 位的小數。- 類型是明確寫出來的(
f64),類型對不上編譯器就拒絕這個程式。這感覺很嚴格,但能在程式執行前抓出錯誤。
為什麼標志 -O 很重要
不加 -O,Rust 會構建一個用於調試的慢版本。加上它,編譯器會做優化。在一臺機器上跑十億步的迴圈:
without -O: 1.18 s
with -O: 0.39 s
(你的數字會不同。)一定要測量發布版本,也就是用 -O 構建的版本;如果用 cargo,就用 cargo build --release。
你的練習
- 安裝 Rust(rustup.rs),保存程式並執行。對照輸出。
- 加上第五個價格,讓程式也列印最差的比值。
- 寫一個函式
max_of(v: &Vec<f64>) -> f64並列印它的結果。 - 用
-O和不用-O分別構建一個 3 億步的迴圈,比較耗時。 - 讓你的智慧體用通俗的話解釋你遇到的第一個編譯器錯誤。
下一步
現在可以讀第 13 課的 Rust 程式碼了。