Так сложились обстоятельства, что у меня возник перерыв в работе, в который я решил переключиться на Rust. Название этого языка резонировало с моим настроением, нашло отклик в душе.
Установка
Как это и бывает с большинством новых инструментов и фреймворков, их установка в основном была простой. Вот только и проходит она с большинством программ не так просто, как должна. Небеспроблемными были на моем верном ноутбуке Windows Surface 3:
- настройка VSCode;
- настройка пакета инструментальных средств.
Настройка VSCode была довольно простой на самом деле: нашел плагин и установил, ничего больше. Остальное — это настройка задач, с которой хорошо знающему VSCode реально разобраться самостоятельно.
О настройке пакета инструментальных средств сообщалось в документах по установке, но четкого объяснения там не было. В конце концов, я зашел на этот сайт для загрузки и запуска выбранных пакетов инструментальных средств C++ 2019 для установки. С их помощью исправляются ошибки компоновщика при наличии таковых.
Написание кода и запуск
Думаю, универсального диспетчера пакетов не существует, поэтому у каждого инструмента он свой. В Rust он называется Cargo. Для создания новых пакетов здесь надо ввести команду cargo new HelloWorld
, для компилирования — команду cargo build
, а для запуска (подождите-ка, вспомню) — cargo run
.
Здорово, что здесь есть команда new
для совсем минимального формирования шаблонов (и оно действительно минимальное): с расширением VS Code задачи уже настроены для сборки, проверки и запуска.
Написание простого кода
Как обычно, начинаю с написания Hello World
(и кто это придумал, Керниган и Ричи? По крайней мере, в «Википедии» так написано!). Затем я написал код по тому, что когда-то было самым популярным вопросом на собеседованиях, а именно написание Фибоначчиевого генератора рекурсивно:
20 лет назад я получил работу, написав именно это решение. Это было еще до того, как Фибоначчи обрел такую популярность, что код по нему мог написать даже ребенок…
При написании этого кода я узнал: 1) как объявлять параметры и возвращать типы; 2) что в Rust не допускается заключать в скобки условия if
; 3) что println()
работает, как большинство операторов печати.
Затем я подумал, что неплохо было бы посмотреть, есть ли здесь оптимизация хвостового вызова. Для этого попробовал переписать Фибоначчи в хвостовую рекурсию. Не то чтобы это было так необходимо, просто взяло верх мое стариковское любопытство. Для удаления хвостовым вызовом стековых кадров, он должен содержать все параметры в самой функции хвостового вызова. Я собирался также сделать версию с мемоизацией, но похоже, что кеш/мемоизация еще не встроены в базовые средства языка Rust.
Другие функциональные возможности языка + мои комментарии
Rust — статически типизированный язык, причем это язык со строгой типизацией (думаю, что сделать его таким было мудрым решением).
Здесь поддерживаются внутренние функции (такие как моя функция inner_fib
, для которой используется двухпроходной компилятор). Так что опережающее объявление имеет место быть.
Здесь обязательно ставить в конце точки с запятой, за исключением операторов return
, что немного странно. Для программиста, написавшего много кода на Python, эти точки с запятой не более чем лишние нажатия клавиш.
Здесь нет цикла «чтение — вычисление — вывод» для быстрого тестирования фрагментов кода, зато есть возможность установить сторонний вычислитель. Не уверен, насколько хорошо он будет тут работать, ведь фактически Rust — компилируемый язык.
Здесь поддерживаются функции высшего порядка как приятный элемент языка функционального программирования.
Похоже, в Rust имеется довольно обширный список функциональных возможностей, надежная библиотека (я с легкостью нашел и использовал функции измерения выполнения кода) и хорошая документация. Не уверен, люблю ли я этот язык, как все остальные, но пока в нем, кажется, есть толк! Возможно, я напишу продолжение после того, как использую Rust еще чуть больше, не ограничившись простым вычислением чисел Фибоначчи.
use std::time::{Instant};
fn main() {
let n = 50;
println!("Hello, world lets run fib tests for size: {}", n);
let start = Instant::now();
println!("Hello fibtail: {}",fib2(n));
let duration = start.elapsed();
println!("--->fibtail perf: {:?}",duration);
let start = Instant::now();
println!("Hello fib: {}",fib(n));
let duration = start.elapsed();
println!("--->fibt perf: {:?}",duration);
}
fn fib(n: i64) -> i64 {
if n == 0 { return 0;}
if n == 1 { return 1;}
return fib (n-1) + fib(n-2);
}
fn fib2(n: i64) -> i64 {
fn fib2_inner(a: i64, b:i64, n:i64) -> i64 {
if n == 0 { return a;}
return fib2_inner(b, a+b, n-1)
}
return fib2_inner(0, 1, n)
}
Читайте также:
- Комбинаторы парсеров: от parsimmon до nom (Typescript → Rust)
- Понятие об умных указателях Rust
- Асинхронный Rust: проблемы и способы их решения
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи Doug Foo: Rust for Old People