Вам также понадобится компоновщик - программа, которую Rust использует для объединения своих скомпилированных выходных данных в один файл. Скорее всего, он у вас уже есть. При возникновении ошибок компоновки, вам следует установить компилятор C, который обычно будет включать в себя и компоновщик. Компилятор C
также полезен, потому что некоторые распространённые пакеты Rust зависят от кода C и нуждаются в компиляторе C.
На macOS вы можете получить компилятор C, выполнив команду:
Пользователи Linux, как правило, должны устанавливать GCC или Clang в соответствии с документацией их дистрибутива. Например, при использовании Ubuntu можно установить пакет build-essential
Установка rustup на Windows
В Windows перейдите на https://www.rust-lang.org/tools/install и следуйте инструкциям по установке Rust. В какой-то момент установки вы получите сообщение о том, что вам также потребуются инструменты сборки MSVC для Visual Studio 2013 или более поздней версии. Чтобы получить инструменты сборки, вам необходимо установить
Visual Studio
2022
. Когда вас спросят, что именно установить, укажите:
“Desktop Development with C++”
The Windows 10 or 11 SDK
Английский языковой пакет вместе с любым другим языковым пакетом по вашему выбору.
В остальной части этой книги используются команды, которые работают как в cmd.exe,
так и в PowerShell. При наличии специфических различий мы объясним, что необходимо сделать в таких случаях.
Устранение возможных ошибок
Чтобы проверить, правильно ли у вас установлен Rust, откройте оболочку и введите эту строку:
Вы должны увидеть номер версии, хэш коммита и дату выпуска последней стабильной версии в следующем формате:
$
xcode-select --install
$
rustc --version rustc x.y.z (abcabcabc yyyy-mm-dd)
Если вы видите эту информацию, вы успешно установили Rust! Если вы не видите эту информацию, убедитесь, что Rust находится в вашей системной переменной
%PATH%
следующим образом:
В Windows CMD:
В PowerShell:
В Linux и macOS:
Если все правильно, а Rust по-прежнему не работает, есть несколько мест, где вы можете получить помощь. Самый простой — это канал #beginners на официальном канале Rust в
Discord
. Там вы можете пообщаться с другими rustaceans (глупое прозвище, которым мы называем себя), которые могут вам помочь. Другие замечательные ресурсы включают форум пользователей и
Stack Overflow
Cargo как КонвенцияВ простых проектах Cargo не даёт больших преимуществ по сравнению с использованием rustc, но он проявит себя, когда ваши программы станут более сложными. Когда программы вырастают до нескольких файлов или нуждаются в зависимостях, гораздо проще позволить Cargo координировать сборку.Не смотря на то, что проект hello_cargo простой, теперь он использует большую часть реального инструментария, который вы будете повседневно использовать в вашей карьере, связанной с Rust. Когда потребуется работать над проектами размещёнными в сети, вы сможете просто использовать следующую последовательность команд для получения кода с помощью Git, перехода в каталог проекта, сборку проекта:Для получения дополнительной информации о Cargo ознакомьтесь с его документацией
ИтогиТеперь вы готовы начать своё Rust путешествие! В данной главе вы изучили как:установить последнюю стабильную версию Rust, используя rustup,обновить Rust до последней версии,открыть локально установленную документацию,написать и запустить программу типа "Hello, world!", используя напрямую компилятор rustc,создать и запустить новый проект, используя соглашения и команды Cargo.$ git clone example.org/someproject $cd someproject $ cargo build
Это отличное время для создания более существенной программы, чтобы привыкнуть читать и писать код на языке Rust. Итак, в главе 2 мы построим программу для игры в угадай число. Если вы предпочитаете начать с изучения того, как работают общие концепции программирования в Rust, обратитесь к главе 3, а затем вернитесь к главе 2.
Программируем игру Угадайка
Давайте погрузимся в Rust, вместе выполнив практический проект! Эта глава познакомит с несколькими распространёнными концепциями Rust, показав, как использовать их в реальной программе. Вы узнаете о let
, match
, методах, ассоциированных функциях,
использовании внешних пакетов и многом другом! В следующих главах рассмотрим эти идеи более подробно. В этой главе вы на практике познакомитесь с основами.
Мы реализуем классическую для начинающих программистов задачу: игру в угадывание.
Вот как это работает: программа генерирует случайное целое число в диапазоне от 1 до
100. Затем она предлагает игроку ввести отгадку. После ввода отгадки программа укажет,
является ли отгадка слишком заниженной или слишком завышенной. Если отгадка верна,
игра напечатает поздравительное сообщение и завершится.
Настройка нового проекта
Для настройки нового проекта перейдите в каталог projects, который вы создали в главе
1, и создайте новый проект с использованием Cargo, как показано ниже:
Первая команда, cargo new
, принимает в качестве первого аргумента имя проекта
(
guessing_game
). Вторая команда изменяет каталог на новый каталог проекта.
Загляните в созданный файл Cargo.toml:
Файл: Cargo.toml
Как вы уже видели в Главе 1, cargo new создаёт программу "Hello, world!". Посмотрите файл src/main.rs:
Файл: src/main.rs
$
cargo new guessing_game
$
cd guessing_game
[package]
name =
"guessing_game"
version =
"0.1.0"
edition =
"2021"
# See more keys and their definitions at https://doc.rust- lang.org/cargo/reference/manifest.html
[dependencies]
Теперь давайте скомпилируем программу "Hello, world!" и сразу на этом же этапе запустим её с помощью команды cargo run
:
Команда run пригодится, когда необходимо ускоренно выполнить итерацию проекта,
мы так собираемся сделать в этом проекте, быстро тестируя каждую итерацию, прежде чем перейти к следующей.
Снова откройте файл src/main.rs. Весь код вы будете писать в этом файле.
Обработка отгадки
Первая часть программы игры угадывания запрашивает ввод данных пользователем,
обрабатывает их и проверяет, что вводимые данные имеют ожидаемую форму. Для начала мы позволим игроку ввести отгадку. Введите код из Листинга 2-1 в src/main.rs.
Файл: src/main.rs
Листинг 2-1: Код, который получает отгадку от пользователя и печатает её
Этот код содержит много информации, поэтому давайте рассмотрим его построчно.
Чтобы получить пользовательский ввод и затем вывести результат в качестве вывода,
fn main
() { println!
(
"Hello, world!"
);
}
$
cargo run
Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
Finished dev [unoptimized + debuginfo] target(s) in 1.50s
Running `target/debug/guessing_game`
Hello, world! use std::io; fn main
() { println!
(
"Guess the number!"
); println!
(
"Please input your guess."
); let mut guess =
String
::new(); io::stdin()
.read_line(&
mut guess)
.expect(
"Failed to read line"
); println!
(
"You guessed: {guess}"
);
}
нам нужно включить в область видимости библиотеку ввода/вывода io
. Библиотека io является частью стандартной библиотеки, известной как std
:
По умолчанию в Rust есть набор элементов, определённых в стандартной библиотеке,
которые он добавляет в область видимости каждой программы. Этот набор называется
прелюдией, и вы можете изучить его содержание в документации стандартной библиотеки
Если тип, который требуется использовать, отсутствует в прелюдии, его нужно явно ввести в область видимости с помощью оператора use
. Использование библиотеки std::io предоставляет ряд полезных функциональных возможностей, включая способность принимать пользовательский ввод.
Как уже отмечалось в главе 1, функция main является точкой входа в программу:
Синтаксис fn объявляет новую функцию, круглые скобки
()
указывают на отсутствие параметров, а фигурная скобка
{
обозначает начало тела функции.
Также в главе 1 упоминалось, что println!
- это макрос, который печатает строку на экран:
Этот код печатает подсказку об игре и запрашивает пользовательский ввод.
Хранение значений с помощью переменных
Далее мы создаём переменную для хранения пользовательского ввода, как показано ниже:
Вот теперь программа становится интересней! Очень многое происходит в этой маленькой строке. Для создания переменной мы используем оператор let
. Вот ещё
один пример:
Эта строка создаёт новую переменную с именем apples и привязывает её к значению 5.
В Rust переменные неизменяемы по умолчанию, то есть, как только мы присвоим use std::io; fn main
() { println!
(
"Guess the number!"
); println!
(
"Please input your guess."
); let mut guess =
String
::new(); let apples =
5
;
переменной значение, значение не изменится. Мы подробно обсудим эту концепцию в разделе
«Переменные и изменчивость».
в Главе 3. Чтобы сделать переменную изменяемой, мы добавляем mut перед её именем:
Примечание: Синтаксис
//
означает начало комментария, который продолжается до конца строки. Rust игнорирует все содержимое комментариев. Подробнее о комментариях мы поговорим в главе 3
Возвращаясь к программе игры Угадайка, теперь вы знаете, что let mut guess предоставит изменяемую переменную с именем guess
. Знак равенства (
=
) сообщает
Rust, что сейчас нужно связать что-то с этой переменной. Справа от знака равенства находится значение, связанное с guess
, которое является результатом вызова функции
String::new
, возвращающей новый экземпляр
String
String
- это тип строки,
предоставляемый стандартной библиотекой, который является расширяемым фрагментом текста в кодировке UTF-8.
Синтаксис
::
в строке
::new указывает, что new является ассоциированной функцией
String типа. Ассоциированная функция - это функция, реализованная для типа, в данном случае
String
. Функция new создаёт новую, пустую строку. Функцию new можно встретить во многих типах, это типичное название для функции, которая создаёт новое значение какого-либо типа.
В целом, строка let mut guess = String::new();
создала изменяемую переменную,
которая связывается с новым, пустым экземпляром
String
. Фух!
Получение пользовательского ввода
Напомним, мы подключили функциональность ввода/вывода из стандартной библиотеки с помощью use std::io;
в первой строке программы. Теперь мы вызовем функцию stdin из модуля io
, которая позволит нам обрабатывать пользовательский ввод:
Если бы мы не импортировали библиотеку io с помощью use std::io в начале программы, мы все равно могли бы использовать эту функцию, записав вызов этой функции как std::io::stdin
. Функция stdin возвращает экземпляр std::io::Stdin
,
который является типом, представляющим дескриптор стандартного ввода для вашего терминала.
let apples =
5
;
// неизменяемая let mut bananas =
5
;
// изменяемая io::stdin()
.read_line(&
mut guess)
Далее строка
.read_line(&mut guess)
вызывает метод read_line на дескрипторе стандартного ввода для получения ввода от пользователя. Мы также передаём
&mut guess в качестве аргумента read_line
, сообщая ему, в какой строке хранить пользовательский ввод. Главная задача read_line
- принять все, что пользователь вводит в стандартный ввод, и сложить это в строку (не переписывая её содержимое),
поэтому мы передаём эту строку в качестве аргумента. Строковый аргумент должен быть изменяемым, чтобы метод мог изменить содержимое строки.
Символ
&
указывает, что этот аргумент является ссылкой, который предоставляет возможность нескольким частям вашего кода получить доступ к одному фрагменту данных без необходимости копировать эти данные в память несколько раз. Ссылки - это сложная функциональная возможность, а одним из главных преимуществ Rust является безопасность и простота использования ссылок. Чтобы дописать эту программу, вам не понадобится знать много таких подробностей. Пока вам достаточно знать, что ссылки,
как и переменные, по умолчанию неизменяемы. Соответственно, чтобы сделать её
изменяемой, нужно написать
&mut guess
, а не
&guess
. (В главе 4 ссылки будут описаны более подробно).
Обработка потенциального сбоя с помощью типа Result
Мы все ещё работаем над этой строкой кода. Сейчас мы обсуждаем третью строку, но обратите внимание, что она по-прежнему является частью одной логической строки кода. Следующая часть - метод:
Мы могли бы написать этот код так:
Однако одну длинную строку трудно читать, поэтому лучше разделить её. При вызове метода с помощью синтаксиса
.method_name()
часто целесообразно вводить новую строку и другие пробельные символы, чтобы разбить длинные строки. Теперь давайте обсудим, что делает эта строка.
Как упоминалось ранее, read_line помещает всё, что вводит пользователь, в строку,
которую мы ему передаём, но также возвращает значение
Result
Result это
перечисление
, часто называемый enum, тип, который может находиться в одном из нескольких возможных состояний. Мы называем каждое такое состояние вариантом.
В главе 6 перечисления будут рассмотрены более подробно. Назначение всех типов
Result заключается в передаче информации для обработки ошибок.
Варианты
Result
:
Ok и
Err
. Вариант
Ok указывает на то, что операция прошла успешно, а внутри
Ok находится успешно сгенерированное значение. Вариант
Err
.expect(
"Failed to read line"
); io::stdin().read_line(&
mut guess).expect(
"Failed to read line"
);