Сильные мира сего приказали нашей команде стать подопытным кроликом, который мигрирует на Rust. Мой подход заключался в настройке различных инструментов, которые мне нравились как разработчику Python для моей среды разработки Rust (RDE). Я был удивлен, когда другие члены команды внедрили многие из моих подходов RDE. Делюсь с вами подробностями.

Мир был бы очень скучным, если бы все использовали одно и то же имя для одного и того же понятия.

Но если подумать, термины не означают одни и те же понятия по веским причинам: каждый термин отличается.

Зависимости в Rust и Python расходятся из-за фундаментальных различий в их языковых парадигмах и форматах упаковки.

Rust — это компилируемый язык со статической типизацией, который распространяет пакеты, известные как ящики, в предварительно скомпилированных двоичных файлах. И наоборот, Python — это интерпретируемый язык с динамической типизацией, пакеты которого распространяются в виде исходного кода.

Разница в методах распространения влияет на установку и управление зависимостями в каждом языке.

Менеджер пакетов Rust, Cargo, интегрирован с компилятором и обеспечивает простое управление зависимостями. И наоборот, в Python есть несколько менеджеров пакетов, наиболее популярным из которых является Pip.

Алгоритм разрешения зависимостей Cargo гарантирует совместимость между всеми пакетами, облегчая управление зависимостями и сводя к минимуму конфликты версий. Разрешение зависимостей Python более расслаблено, что иногда приводит к конфликтам версий.



Эти несоответствия между зависимостями в Rust и Python в конечном итоге проистекают из уникальных приоритетов и целей разработки каждого языка.

Rust делает упор на производительность строго типизированного скомпилированного языка, многопоточность для современных многоядерных компьютеров и безопасность для C. Python делает упор на простоту использования и удобочитаемость.

Установка Rust и Cargo

Установка, которую я и мои товарищи по команде используем, взята с https://doc.rust-lang.org/book/ch01-01-installation.html. Сообщество Rust поддерживает его, и это быстро, менее 1 минуты, на моем MacPro 2013 со старым чипсетом Intel Xeon E5.

curl https://sh.rustup.rs -sSf | sh

Примечание. shможет не работать. использовать /bin/bash

Jupyter не является интегрированной средой разработки (IDE)

Jupyter — это интерактивная среда для вычислений и исследования данных, довольно популярная в сообществе Python и машинного обучения. Особое внимание я уделяю интерактивной вычислительной среде (ICS), также известной как цикл чтения-оценки-печати или редактор REPL.

Я начал свою карьеру в области вычислений на IBM 360, используя перфокарты и выполняя компиляцию каждые 12 часов; если бы мой день начался в 2 часа ночи.

Я использую Jupyter для Python.

Что-то другое будет лучше Jupyter, но с использованием Python и Jupyter; Я перешел от количества компиляций в час к тому, сколько функций я могу написать в час с пятью модульными тестами.

Не лги. Я примерно в 25 раз продуктивнее работаю с Python/Jupyter, чем с C/Emacs.

Jupyter обладает некоторыми функциями, обычными для интегрированных сред разработки (IDE), включая редактирование кода и отладку.

Основная цель Jupyter — обеспечить интерактивные вычисления, анализ данных и исследовательское программирование, что делает его незаменимым инструментом для таких задач, как кодирование и отладка, а также очистка, преобразование и визуализация данных.

Я использую и ICS, и IDE. Я использую ICS, Jupyter, чтобы доработать кучу связанных функций, а для IDE я использую Pycharm с плагином Rust для развертывания в Test. Я более подробно опишу плагин Rust далее в этой статье.

Как настроить Jupyter как ICS для Rust

Я хочу, чтобы Jupyter экспериментировал с кодом Rust.

ExCxR for Jupyter — это проект с открытым исходным кодом (бесплатный!), который позволяет выполнять код Rust в блокноте Jupyter.

Чтобы использовать Rust в Jupyter, вы должны установить и поместить ядро ​​в свою среду Jupyter.

Я покажу вам шаг за шагом:

Примечание. Я предполагаю, что вы знакомы с Python. Если нет, я рекомендую использовать документацию Rust.

  1. Возможно, у вас уже установлен Jupyter. Если вы этого не сделаете, установите Jupyter через загрузчик Python:
pip install jupyter

2. Затем загрузите и соберите крейт evcxr, выполнив в терминале следующую команду:

cargo install evcxr_jupyter

3. Затем установите ядро ​​evcxr_jupyter, выполнив в терминале следующую команду:

evcxr_jupyter --install

4. Вы можете запустить сервер ноутбуков Jupyter с помощью команды jupyter notebook:

jupyter notebook

5. Создайте новый блокнот Rust: в интерфейсе блокнота Jupyter нажмите Создать -> Rust, чтобы создать новый блокнот Rust.

6. Скопируйте и вставьте код из предыдущего ответа в ячейку блокнота.

7. Запустите код, нажав Shift+Enter или нажав кнопку «Выполнить» в интерфейсе блокнота. Вот пример того, как код Rust «Hello, world» и вывод отображаются в блокноте Jupyter:

Функция Hello-World, скомпилированная и выполненная в Jupyter! Это так круто!

Вот пример рекурсивной версии функции Фибоначчи в Rust для вычисления n-го числа Фибоначчи:

Примечание. Разбейте evcxr_jupyter на fibnacci(100)..

Примечание. Возможно, вам потребуется настроить параметры блокнота Jupyter для отображения вывода программы Rust, который может не отображаться по умолчанию. Вы можете сделать это, выбрав «Ячейка» -> «Все выходные данные» -> «Переключить прокрутку» в строке меню.

Комментарии

Отличительной особенностью Python является его удобочитаемость для людей.

В Rust, если вы написали код, его можно прочитать в тот же день. В следующем месяце не очень.

Если вы выпустите свой код Rust для тестирования без комментариев или вредоносных комментариев, ваш код будет одним из последних, прошедших тест. Как несправедливо!

Примечание. Мы тестируем, но называем группу контроля качества — Test.

В Rust есть официальное руководство по стилю для комментариев, которое можно найти в Документации Rust.

По крайней мере, мы думаем, что понимаем, чего добилось сообщество Rust с помощью своего руководства по стилю комментариев. Его также можно использовать в качестве руководства по стилю для C.

Однако, ИМХО, Rust нуждается в большом количестве комментариев, чтобы его можно было прочитать.

Вот что мы сделали для нашего руководства по стилю. Мы объединили Руководство по стилю Google Rust и Руководство по стилю Google Python и получили два правила стиля комментариев Rust:

  1. Используйте комментарии к документам для документирования крейтов, функций, методов, структур, перечислений, трейтов и модулей. Комментарий документа — это комментарий, начинающийся с /// или /**. Документация предоставляет общий обзор того, что делает элемент, как он работает, а также любые важные детали, относящиеся к пользователям элемента.

Например:

/// functiion sum: Returns the sum of two numbers.
/// # Examples
///
/// ```
/// let result = sum(2, 3);
/// assert_eq!(result, 5);
/// ```
fn sum(a: i32, b: i32) -> i32 {
    a + b
}

Аргументы в этом примере недокументированы, поскольку они самостоятельно документируют имя, имя аргумента и тип. Если используемые аргументы неочевидны, то они должны быть задокументированы.

2. Не используйте встроенные комментарии. Если вы чувствуете, что должны использовать /* ... */ НА СТРОКЕ ВЫШЕ, чтобы предоставить детали реализации, не относящиеся к пользователям кода.

Используйте встроенные комментарии экономно и только в случае необходимости. Встроенные комментарии должны предоставлять дополнительный контекст или объяснять сложный код, но код должен быть не требующим пояснений, когда это возможно.

Например:

fn main() {
    let x = 5; // BAD INLINE COMMENT Initialize x to 5
// GOOD, BUT NOT REALLY. SORT OF OBEYS STYLE RULE
// Add 2 to x to get y
    let y = x + 2;
    println!("The value of x is {} and the value of y is {}", x, y);
}

Мы используем комментарии в нашем коде на Rust, поэтому он хорошо документирован и удобочитаем для вас и других, кто может следовать.

Помните, что мы находимся (были) под сильным влиянием Python и являемся новичками в Rust. Наши методы комментирования Rust могут вам не подойти.

Вероятно, наши методы комментариев (doc) в Rust будут развиваться дальше.

Интегрированные среды разработки Rust (IDE)

Вся информация была собрана из блогов разработчиков, сплетен программистов, а иногда и из документации по продукту.

Функции среды IDE, которую мы используем сейчас, JetBrains PyCharm (или IntelliJ IDEA) с плагином Rust, заслуживают одной или нескольких статей в блоге. Никаких обещаний, но вы можете увидеть их в будущем.

Я знаю более восьми IDE. В этом внешнем блоге я кратко обсудил четыре IDE (интегрированные среды разработки), которые поддерживают несколько языков, включая Rust.

Visual Studio для Rust

Если вы используете платформу Windows, я слышал от других коллег, что Visual Studio — отличная IDE для Rust. Это может быть здорово для MacOS и Linux. Однако мы остановились на документации Visual Studio for Rust. Его не было для macOS. Возможно, мы недостаточно внимательно искали. Там была отличная документация для Microsoft Windows.

Представьте себе наше удивление, когда мы пришли к выводу, что Microsoft необходимо полностью поддерживать macOS или Linux от Apple.

Примечание. Хорошо, мы не были так уж удивлены.



Плагин JetBrains IntelliJ IDEA Rust

Выбираем плагин JetBrains для Rust. Установка плагина Rust в PyCharm прошла без особых усилий.

Кроме того, у него была потрясающая, но бесполезная функция. Если бы мы запустили PyCharm перед загрузкой, страница загрузки плагина Rust изменилась бы.

Установите плагин Rust, а затем вам, возможно, придется перезапустить PyCharm.

Документация для плагина IntelL (PyCharm) неплохая, ИМХО.



Особенности плагина PyCharm для Rust:

  1. Подсветка и завершение кода;
  2. Интеграция с Cargo: Плагин интегрируется с Cargo, менеджером пакетов Rust (менеджером проектов);
  3. Полная интеграция с GitHub;
  4. Отладка: плагин включает встроенный отладчик;
  5. Тестирование: плагин включает поддержку запуска тестов Rust и предоставляет окно инструмента запуска тестов для отображения результатов тестов.
  6. Документация: Плагин обеспечивает быстрый доступ к документации Rust в среде IDE.

Если будет достаточно интереса, как показано в комментариях, я напишу статью в блоге о различных функциях, которые мы используем в плагине IntelliJ IDEA для Rust.

Затмение

Мы использовали Eclipse для небольшого проекта Scala. Это было хорошо. Мы обнаружили, что он занимает много памяти, долго загружается и неудобен в использовании. Правда, мы использовали его два года назад и уже использовали PyCharm.

Если вы не знакомы с Rust IDE, Eclipse — хороший выбор.

Emacs

Если вы использовали Emacs в течение 30 или более лет, вы должны остаться с Emacs. Если вы вложили значительные средства в макросы Lisp (Scheme), вы хотите остаться с Emacs.

Хорошая новость заключается в том, что Emacs — это текстовый редактор (Lisp) с широкими возможностями настройки и хорошей поддержкой Rust в режиме Rust. Плохая новость в том, что вы будете одиноки.

Версии, зависимости, совместимость

Я не уверен, должен ли я вам говорить, но вы можете скомпилировать и запустить с помощью команды rustc.

Никто, буквально, никто, кого я знаю, не использует rustc,все, кого я знаю, использует cargo.

Если вы установили среду ржавчины, следуя процедуре установки, описанной выше, то ввод на вашем терминале должен привести к чему-то вроде следующего:

Если он не отображает версию, попробуйте установить еще раз.

Большая часть остальной части этой статьи в блоге будет сбивать с толку, пока вы не заработаете cargo.

Груз

Большинство пользователей Rust используют этот инструмент (cargo) для управления своими проектами на Rust, потому что Cargo выполняет за вас множество задач… документацию rust.

Cargo выигрывает от всех менеджеров пакетов, которые были до него. Pip — отличный пример далеко не оптимального менеджера пакетов.

  1. Cargo является частью Rust. Cargo (обычно) устанавливается вместе с Rust;
  2. cargo new <project-name> создает каталог <project-name>, создает минимальную структуру подкаталогов, инициализирует его как локальный репозиторий git и создает важные файлы cargo.toml.

Кроме того, вы можете присоединиться к существующему проекту с существующим репозиторием сервера Rust git. Например, репозиторий этой статьи в блоге — https://github.com/bcottman/rustDevEnv.

# cd <to directory to place local copy of repo>
$ git clone https://github.com/bcottman/rustDevEnv.git
$ cd rustDevEnv
$ ls -alx

Структура каталогов и файлы после git clone для проекта rustDevEnv:

Мы сочли, что лучше всего, поскольку над проектом обычно работает более одного разработчика, иметь одного разработчика:

  1. Создайте проект ржавчины, используя cargo new <project-name>;
  2. Затем создайте репозиторий проекта на сервере git.

Все остальные разработчики теперь могут клонировать репозиторий сервера git.

Примечание. Если у вас была версия git более года, вам следует обновить ее. Версия git, которую я использую:

3. cargo build завершает инициализацию локального проекта как проекта rust с src/main.rs(code for hello world), компиляцией, загрузкой зависимостей (ящиков), указанных в cargo.toml file, и ссылками для создания исполняемого файла. Локальный каталог проекта теперь:

Большой. cargo build указывает, что я должен использовать rest_dev_env , а не restDevEnv.

4. cargo checkкомпилирует, но не создает исполняемый файл. Это быстрее, и поэтому вы можете получить больше компиляций за миллисекунду.

5. cargo build --release скомпилировать его с оптимизацией и поместить исполняемый файл в ../target/release.

6. cargo run

7. cargo testищет атрибут #[test] в вашем коде Rust, чтобы запускать их как тесты.

8. rustdoc src/<filename> -crate-name <name>

Примечание. Я считаю, что Cargo является менеджером проекта непрерывной разработки (CD). CD является частью CD/CI, которая определяет DevOps.

Грамотное программирование

Около двух лет назад я обсуждал идею двадцатилетней давности Дональда Кнута под названием грамотное программирование.



Основная идея заключается в том, что код и связанные тесты и документация для этого кода находятся в одном исходном файле. Конечно, в вашем проекте (корзине) может быть много разных исходных файлов.

Для меня cargo достигает «грамотного программирования» для Rust.

Другое важное преимущество cargo заключается в том, что он управляет зависимостями и обеспечивает совместимость между различными версиями крейтов Rust. Кроме того, cargo тесно интегрирован с Git и извлекает зависимости из репозиториев Git.

Jupyter нужно работать с ржавым проектом.

Ранее я обсуждал чудеса совместимости Juptyer с Rust. Я имел в виду, что вы можете поместить любой ржавый код в Jupyter и оценить его.

Вы можете делать это до тех пор, пока в коде Rust нет зависимых крейтов. Например, следующий код Rust, вырезанный и вставленный в блокнот Jupyter, не работает:

extern crate num_cpus;

fn main() {
    let num_cores = num_cpus::get();
    println!("Number of cores: {}", num_cores);
}

main()

Тем не менее, это сработает, если вы настроили проект Rust с cargo build и поместили num_cpus в crate.toml в качестве зависимости крейта.

Стоит повторить, Jupyter должен запускаться в каталоге проекта со всеми зависимыми крейтами, указанными в файле crate.toml..

Примечание. Для вас может быть очевидным, но не для нас, что вам нужно поместить каждый ящик и номер версии этого ящика в раздел [dependecy] списка crate.toml. Dependectcy в crate.toml. не генерируется из исходного кода. Возможно. Позвольте мне, если есть инструмент, который делает это.

Примечание. Доступно около 50 000 ящиков, а номера версий можно найти на https://crates.io/. К вашему сведению, у pyhon около 500 000 пакетов на https://pypi.org/.

Тестирование

cargo test — это инструмент командной строки, включенный в систему сборки Rust Cargo. Он используется для запуска тестов в проекте Rust.

Добавьте атрибут #[test], чтобы пометить код как тестовый.

Когда вы запустите cargo test, Cargo скомпилирует код вашего проекта, включая любые модульные тесты, и запустит их.

Чтобы специализировать свои тесты, вы можете использовать различные параметры командной строки для управления запускаемыми тестами. Например:

  • cargo test <test_name> запустит только тест с указанным именем.
  • cargo test -- --ignored будет запускать только тесты, отмеченные атрибутом #[ignore].
  • cargo test --release запустит тесты с включенной оптимизацией, что ускорит их выполнение и усложнит отладку.

Дополнительно cargo test после запуска указанных тестов выводит результаты тестов на консоль. Вывод будет включать информацию о том, какие тесты пройдены и не пройдены, а также любые выходные данные, созданные самими тестами.

Я покажу, как ведет себя cargo test, начав с примера реализации рекурсивной функции Фибоначчи со степенью n как:

fn fibonacci(n: i32) -> i32 {
    if n < 0 {
        panic!("Fibonacci sequence is only defined for non-negative numbers");
    }
    if n == 0 {
        0
    } else if n == 1 {
        1
    } else {
        fibonacci(n - 1) + fibonacci(n - 2)
    }
}

Добавить модульные тесты очень просто:

#[test]
fn test_fbonacci_first() {
    assert_eq!(fibonacci(0), 0);
}
#[test]
fn test_fbonacci_fail() {
    assert_eq!(fibonacci(0), -1);
}
#[test]
fn test_fbonacci_rest() {
    assert_eq!(fibonacci(1), 1);
    assert_eq!(fibonacci(2), 1);
    assert_eq!(fibonacci(3), 2);
    assert_eq!(fibonacci(4), 3);
    assert_eq!(fibonacci(5), 5);
    assert_eq!(fibonacci(6), 8);
    assert_eq!(fibonacci(7), 13);
}

cargo test в проекте RustDevEnv, и результат будет таким:

Если вы хотите усложнить тестирование, а я надеюсь, что вы это сделаете, прочитайте https://doc.rust-lang.org/book/ch11-01-writing-tests.html.

Я дал представление о том, что вы можете сделать для тестирования в Rust. Другие ящики, на которые стоит обратить внимание:

  1. Criterion.rs – это отличный набор инструментов для сравнительного анализа вашего кода на Rust. Он обеспечивает статистический анализ результатов тестов и позволяет сравнивать производительность различных реализаций.
  2. Proptest – это среда тестирования на основе свойств, которая генерирует случайные входные данные, чтобы убедиться, что ваш код ведет себя правильно для всех возможных входных данных. Это мощный инструмент для обнаружения крайних случаев и повышения надежности вашего кода.
  3. Если ваш код на Rust зависит от внешних зависимостей, Mockers — отличный инструмент для написания тестов. Это позволяет вам определять фиктивные объекты и проверять, правильно ли они используются.

Тестовых фреймворков Rust гораздо больше, и ежедневно выпускаются новые. Пожалуйста, продолжайте оценивать инструменты тестирования Rust по мере их появления. Я знаю, я буду.

Будущая работа

С чего начать? Rust — это совершенно новая языковая экосистема для меня.

Вот пара вопросов, которые у меня есть.

Polar пользуется большим успехом в нашей группе. Для тех, кто не знаком с Polars, это реализация Pandas на Rust, которая работает быстро и решает большинство проблем с большими данными, которые есть у Pandas. Должны быть другие пакеты Python, которые есть в Rust. Кто они такие? Какие новые ящики мы можем ожидать?

Должны ли мы использовать инструменты Rust git или ограничиваться действиями Github?

Я не обсуждал отладчики в этой статье блога, потому что мы все еще выбираем отладчики. Внутренний аргумент заключается в том, будем ли мы придерживаться отладчика плагинов IntelliJ Rust? Станет ли лучше?

Уверен, что будут еще вопросы. Что мне пока нравится в Rust, так это то, что он исправляет многие проблемы с C. Меня не устраивает отсутствие объектно-ориентированного подхода в ядре Rust.

Ржавчина++? Без комментариев.

Помните, что вы получаете RustDevEnv и весь связанный с ним код, клонируя репозиторий GitHub по адресу https://github.com/bcottman/rustDevEnv.

Ресурсы

Язык программирования Rust

Записные книжки Rust с Evcxr

Плагин JetBrian (IntelliJ IDEA) Rust

Mac IDE — разработка приложений и игр на Mac OS

Пример строки документации Python в стиле Google

Руководство по стилю Google Python

Плагин Rust для Pycharm

Установить Visual Studio для Mac

Rust с кодом Visual Studio

Документация по коду Visual Studio

crates.io: Реестр пакетов Rust

ПиПИ

Спасибо!