Строки, функции и ящики / модули
В нашей серии dna_toolkit мы широко использовали строки, списки и словари Python. Эти структуры данных очень полезны и делают нашу жизнь очень простой. Посмотрим, что может предложить Rust.
Начнем с Strings
. Ржавчина бывает двух типов. Один называется «Строка», а другой больше похож на строку в других языках, то есть просто «Строка». Я собираюсь дать ссылку на потрясающее видео о строках в Rust в разделе «Ссылки» ниже. Обязательно посмотрите его, если вы новичок в этой части Rust.
В этой статье мы сосредоточимся на рассмотрении того, как мы можем использовать строки в Rust для репликации некоторых из нашего кода «dna_toolkit». В предыдущей статье мы создали два файла для Rust и Python: «main.rs» и «main.py» соответственно. Мы добавили весь код в эти два файла.
Чтобы избежать добавления большого количества кода в один файл, давайте создадим отдельные файлы для каждого видео, превратим код в функции и включим / импортируем их в наши «основные» файлы.
Итак, вот структура проекта, которую мы создали в нашей первой статье:
Создадим два новых файла; intro.py и intro.rs, переместите весь код из наших основных файлов в эти файлы и включите / импортировать их. Итак, теперь наш проект должен выглядеть так:
Теперь, когда мы создали структуру, которую будем использовать, давайте добавим еще два файла под названием «строки» и перейдем к нашему первому сегменту.
Часть 1: Струны
Итак, теперь у нас должно получиться что-то вроде этого:
Обратите внимание, что мы добавили символ подчеркивания в наши функции Rust: _intro (), _strings (). Это сделано, чтобы избежать появления этого предупреждающего сообщения компилятора:
= note: `#[warn(dead_code)]` on by default
Мы закомментируем вызовы предыдущих функций, чтобы избежать одновременного вывода большого количества результатов, поэтому мы можем сосредоточиться только на выводе кода текущей статьи. В этом случае Rust сообщает нам, что существует «мертвый код», что означает, что у нас есть функция _intro (), которая включена, но никогда не вызывается. Это не проблема, просто не забудьте добавить подчеркивание ко всем функциям Rust, которые вы не используете / не вызываете.
Мы сосредоточимся на String, поскольку это структура данных, размещенная в куче, то есть мы можем изменять ее во время выполнения, и она имеет набор очень полезных методов.
Python не заботится о том, добавляете ли вы «символ» или другую «строку» к нашей основной строке, но Rust строго к этому относится. Здесь у нас есть два метода Rust для:
- push_str (««); - добавляет строку. Требуются двойные кавычки ““. Строка 4.
- push (‘‘); - добавляет один символ. Требуются одинарные кавычки ‘. Строка 7.
Если в Python мы просто говорим test_str = "Doom"
и Python понимает, что это строка, в Rust нам нужно явно указать компилятору: let mut test_str = String::from("Doom");
Вы также можете создать пустую строку следующим образом: let mut test_str = String::new();
Оба кода выведут это:
Ознакомьтесь с некоторыми другими методами, которые есть в Rust String: https://www.tutorialspoint.com/rust/rust_string.htm
Давайте объединим две существующие строки:
В Python это просто. Это просто работает, и мы можем продолжить доступ ко всем трем переменным после того, как запустим этот код.
Если мы попытаемся сделать то же самое в Rust, мы столкнемся с проблемой. Давайте взглянем:
Обратите внимание, что когда мы добавляем строки, первая строка не имеет символа амперсанда &. Каждая строка, которую мы добавляем после этого, должна содержать символ &.
Если мы запустим это, мы увидим эту проблему:
println!("{} {} {}", p1, p2, p3); | ^^ value borrowed here after move
В строке 4 мы передали p3 право собственности на p1 и снова пытаемся получить к нему доступ в строке 5, распечатав его. p1 на данный момент не существует, так как право собственности перешло к p3.
Нам нужно использовать функцию Rust 'format!, которая будет «занимать» ячейки памяти p1 и p2 для создания p3 и не повлияет на владение какой-либо переменной:
Теперь мы повторили поведение Python. Оба должны вывести это:
Duke Nukem Duke Nuke
Теперь давайте кратко рассмотрим, как можно распечатать отдельные символы, индексы и часть строки (фрагмент):
Как видите, код выглядит очень похоже. В Rust мы используем метод chars()
для получения одного символа и char_indices()
для получения индекса и символа. Нарезка практически идентична.
Часть 2: Модуль Rand (ящик)
Теперь, когда мы вооружены базовыми знаниями Rust String, давайте быстро перенесем две функции «DNA Toolkit». Для этого нам понадобится генератор случайных чисел. Модуль random является частью Python и может быть просто включен и использован, но в Rust нам нужно добавить его как зависимость, построить его, и только тогда мы сможем его использовать. Но это очень просто, как вы увидите.
Конфигурацию зависимостей проекта можно найти в Cargo.toml
файле:
Прежде чем мы просто слепо добавим модуль, давайте посмотрим, как мы можем его найти. Откройте свой терминал, убедитесь, что он находится в папке «dna_engine», или воспользуйтесь встроенным терминалом и выполните cargo search
для поиска rand
модуля (контейнера).
В списке результатов поиска мы видим rand
:
Теперь давайте добавим его в наш проект. Измените Cargo.toml
Строку 7-8 файла, чтобы она выглядела так:
Вот и все. Когда мы закончим писать функцию (следующий сегмент), которая будет нуждаться в этом модуле, и запустим эту функцию, Rust увидит, что мы пытаемся использовать этот модуль. Он увидит, что мы добавили его в [dependencies]
, и скачает / построит его для нас.
Часть 3: Генерация случайных последовательностей ДНК
Давайте добавим два новых файла: dna_toolkit.py
и dna_toolkit.rs
. Здесь будут жить две наши новые функции.
Итак, вот наша функция генерации случайной последовательности ДНК: (мы используем цикл в Python вместо понимания списка в демонстрационных целях)
Структура очень похожа.
- Строка 1: Мы импортируем / включаем случайные модули. выбор / ранд.
- Строка 3: В Python нам не нужно указывать тип параметра и тип возвращаемого значения, в Rust это нужно делать.
length: i32
сообщает компилятору, что мы будем передавать целое число в нашу функцию, а-> String
часть сообщает компилятору, что мы вернем строку. - Строка 8: Код Python определенно выглядит чище, но Rust читать не намного сложнее. Мы просто просим модуль
rand
сгенерировать случайное число в диапазоне от0
доlength
вектора, содержащего 4 символа нуклеотида. Мыpush
этот случайно выбранный символ в нашей строке. Единственный лишний бит, который у нас есть, - этоthread_rng()
. Согласно документации Rust: 'Получить лениво инициализированный локальный генератор случайных чисел потока, засеянный системой'
Часть 4: транскрипция ДНК в РНК
При транскрипции нам просто нужно заменить все нуклеотиды «Т» - тимина на «U» - урацил. Это делается с помощью только одной строчки кода в каждой, поскольку Python и Rust имеют для этого встроенные функции:
Легко, правда? Теперь давайте посмотрим на оба файла рядом:
А давайте попробуем добавить результат в наши main
файлы, чтобы протестировать наши новые функции:
И вот результаты обоих:
А вот как должна выглядеть наша файловая структура:
Это все для этой статьи. Теперь мы знаем, как создавать строки и манипулировать ими в Rust. Как написать простую функцию, передать ей параметр и вернуть значение. Мы также узнали, как добавить модуль (ящик) в Rust и включить файлы в другие файлы.
Ссылки
- Видео Rust String: https://youtu.be/ClPrjjHmo2Y
- Дополнительные методы Rust String: https://www.tutorialspoint.com/rust/rust_string.htm
Рекомендуемые книги по программированию на Rust
- Язык программирования Rust. (США / Великобритания)
- Освоение Rust: узнайте о безопасности памяти, системе типов, параллелизме и новых функциях Rust 2018 edition, 2nd Edition. (США / Великобритания)