Вспомогательный урок к курсу "Собери своего арбитражного бота". В занятии 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 build --release, если используешь cargo.
Твое упражнение
- Установи Rust (rustup.rs), сохрани программу и запусти. Сверь вывод.
- Добавь пятую цену и сделай так, чтобы программа печатала еще и худшее отношение.
- Напиши функцию
max_of(v: &Vec<f64>) -> f64и выведи ее результат. - Собери цикл в 300 миллионов шагов с
-Oи без и сравни время. - Попроси агента объяснить простыми словами первую ошибку компилятора, которую встретишь.
Что дальше
Теперь можно читать код на Rust из занятия 13.