- Оригинальный адрес:Your first CLI tool with Rust
- Оригинальный автор:Jérémie Veillet
- Перевод с:Программа перевода самородков
- Постоянная ссылка на эту статью:GitHub.com/rare earth/gold-no…
- Переводчик:JackEggie
- Корректор:TloveYing
В прекрасном мире программирования вы, возможно, слышали об этом новом языке под названием Rust. Это язык программирования системного уровня с открытым исходным кодом. Основное внимание уделяется производительности, безопасности памяти и параллелизму. На нем можно писать низкоуровневые приложения, такие как C/C++.
ты уже можешь бытьWeb AssemblyУвидел на сайте. Rust умеет компилировать приложения WASM, вы можетеWeb Assembly FAQНайдите много примеров на . Он также считаетсяservoКраеугольным камнем Servo является высокопроизводительный движок браузера, реализованный в Firefox.
Это может вас оттолкнуть, но мы не об этом. Мы покажем вам, как использовать его для создания инструментов командной строки, и вы можете найти в нем много интересного.
Почему ржавчина?
Ну, позвольте мне прояснить ситуацию. Я мог бы сделать инструменты командной строки на любом другом языке или фреймворке. Я могу выбрать C, Go, Ruby и т. д. Даже я могу использовать классический bash.
В середине 2018 года мне захотелось узнать что-то новое, Rust разжег мое любопытство, а также мне нужно было создать несколько простых гаджетов для автоматизации некоторых процессов в работе и личных проектах.
Установить
ты можешь использоватьRustupдля настройки вашей среды разработки, это основная точка входа для установки и настройки всех инструментов Rust на вашем компьютере.
Если вы работаете в Linux и MacOS, установку можно выполнить с помощью следующей команды:
$ curl <https://sh.rustup.rs> -sSf | sh
Если вы используете систему Windows, опять же, вам необходимоСайт Rustupскачать одинexe
и беги.
Если вы используете Windows 10, я рекомендую вам использоватьWSLдля завершения установки. Это все, что нужно для установки, и теперь мы готовы создать наше первое приложение на Rust!
Ваше первое приложение на Rust
То, что мы собираемся сделать здесь, это по образцуcatдля создания UNIX-утилиты или, по крайней мере, упрощенной версии, назовем ееkt
. Это приложение примет путь к файлу в качестве входных данных и отобразит содержимое файла на стандартном выходе терминала.
Чтобы создать базовый скелет этого приложения, мы будем использоватьCargoИнструмент. Это менеджер пакетов Rust, думайте о нем как о NPM (для разработчиков Javascript) или Bundler (для разработчиков Ruby) для инструментов Rust.
Откройте терминал, перейдите по пути, по которому вы хотите сохранить исходный код, и введите следующий код.
$ cargo init kt
Это создаст файл с именемkt
каталог, в котором уже есть базовая структура нашего приложения.
если мыcd
в этот каталог, мы увидим эту структуру каталогов. И, что удобно, в этом проекте по умолчанию уже инициализирован git. Отлично!
$ cd kt/
|
.git/
|
.gitignore
|
Cargo.toml
|
src/
Cargo.toml
Файл содержит основную информацию и информацию о зависимостях нашего приложения. Точно так же вы можете думать об этом как о приложении.package.json
илиGemfile
документ.
src/
Каталог содержит исходные файлы для приложения, мы видим, что там только одинmain.rs
документ. Проверив содержимое файла, мы видим, что есть только одинmain
функция.
fn main() {
println!("Hello, world!");
}
Попробуйте создать этот проект. Поскольку внешних зависимостей нет, сборка должна происходить очень быстро.
$ cargo build
Compiling kt v0.1.0 (/Users/jeremie/Development/kitty)
Finished dev [unoptimized + debuginfo] target(s) in 2.82s
В режиме разработки вы можете сделать это, вызвавcargo run
выполнить двоичный файл (сcargo run --- my_arg
для передачи аргументов командной строки).
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.07s
Running `target/debug/kt`
Hello, world!
Поздравляем, у вас есть первое приложение на Rust, и вы только что выполнили шаги! 🎉
Разобрать первый аргумент командной строки
Как я уже говорил ранее в статье, мы пытаемся построить упрощенную версиюcat
Заказ. Наша цель — смоделироватьcat
поведение, бегаkt myfile.txt
После команды выведите содержимое файла в терминал.
Мы могли бы сами справиться с процессом анализа параметров, но, к счастью, есть инструмент Rust, который может помочь нам упростить этот процесс, а именно:Clap.
Это высокопроизводительный анализатор аргументов командной строки, который упрощает управление аргументами командной строки.
Первым шагом в использовании этого инструмента является открытиеCargo.toml
файл и добавьте в него указанные зависимости. если вы никогда не имели дело с.toml
файл не имеет значения, он такой же, как.INI
Файлы очень похожи. Этот формат файла распространен в Rust.
В этом файле вы увидите, что некоторая информация уже заполнена, например, автор, версия и т. д. нам просто нужно[dependencies]
Просто добавьте зависимости ниже.
[dependencies]
clap = "~2.32"
После сохранения файла нам нужно пересобрать проект, чтобы иметь возможность использовать библиотеку зависимостей. Несмотря на тоcargo
скачать кромеclap
Не беспокойтесь о файлах, отличных отclap
Также имеет необходимые зависимости.
$ cargo build
Updating crates.io index
Downloaded clap v2.32.0
Downloaded atty v0.2.11
Downloaded bitflags v1.0.4
Downloaded ansi_term v0.11.0
Downloaded vec_map v0.8.1
Downloaded textwrap v0.10.0
Downloaded libc v0.2.48
Downloaded unicode-width v0.1.5
Downloaded strsim v0.7.0
Compiling libc v0.2.48
Compiling unicode-width v0.1.5
Compiling strsim v0.7.0
Compiling bitflags v1.0.4
Compiling ansi_term v0.11.0
Compiling vec_map v0.8.1
Compiling textwrap v0.10.0
Compiling atty v0.2.11
Compiling clap v2.32.0
Compiling kt v0.1.0 (/home/jeremie/Development/kt)
Finished dev [unoptimized + debuginfo] target(s) in 33.92s
Вышеупомянутое — это то, что нужно настроить, а затем мы можем начать и написать некоторый код для чтения нашего первого параметра командной строки.
Открытымmain.rs
документ. Мы должны явно заявить, что хотим использовать библиотеку Clap.
extern crate clap;
use clap::{Arg, App};
fn main() {}
extern crate
Ключевое слово используется для импорта зависимых библиотек, вам просто нужно добавить его в основной файл, и любой исходный файл вашего приложения может ссылаться на него.use
раздел относится к тому, что вы будете использовать в этом файлеclap
какой модуль.
Краткое описание модулей Rust:
В Rust есть модульная система, позволяющая организованно повторно использовать код. Модуль — это пространство имен, содержащее определения функций или типов, и вы можете выбрать, будут ли эти определения видны вне его модуля (общедоступного или частного). - Документация по ржавчине
Здесь мы заявляем, что хотим использоватьArg
иApp
модуль. Мы хотим, чтобы наше приложение имелоFILE
параметр, он будет содержать путь к файлу. Clap может помочь нам быстро реализовать эту функцию. Здесь есть способ цепочки вызовов методов, что очень приятно.
fn main() {
let matches = App::new("kt")
.version("0.1.0")
.author("Jérémie Veillet. jeremie@example.com")
.about("A drop in cat replacement written in Rust")
.arg(Arg::with_name("FILE")
.help("File to print.")
.empty_values(false)
)
.get_matches();
}
Скомпилируйте и выполните снова, за исключением переменнойmatches
скомпилировать предупреждения (для разработчиков Ruby вы можете добавить переменную_
, который говорит компилятору, что переменная является необязательной), она не должна выводить многое другое.
Если вы пройдете приложение-h
или-V
параметры, программа автоматически создаст справочное сообщение и информацию о версии. Я не знаю, что вы думаете об этом, но я думаю, что это 🔥🔥🔥.
$ cargo run -- -h
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Running `target/debug/kt -h`
kt 0.1.0
Jérémie Veillet. jeremie@example.com
A drop-in cat replacement written in Rust
USAGE:
kt [FILE]
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
ARGS:
<FILE> File to print.
$ cargo run --- -V
Finished dev [unoptimized + debuginfo] target(s) in 0.04s
Running target/debug/kt -V
kt 0.1.0
Мы также можем попробовать запустить программу без каких-либо аргументов и посмотреть, что произойдет.
$ cargo run --
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Running `target/debug/kt`
Ничего не случилось. Это поведение по умолчанию, которое должно происходить каждый раз, когда создается инструмент командной строки. Я не думаю, что какое-либо действие должно запускаться без передачи каких-либо параметров приложению. Хотя иногда это и не так, в большинстве случаев никогда не делайте того, что пользователь никогда не собирался делать.
Теперь, когда у нас есть параметры, мы можем копаться в том, какзахватыватьЭтот аргумент командной строки и печатает что-то на стандартный вывод.
Для этого мы можем использоватьclap
серединаvalue_of
метод. Пожалуйста, обратитесь кДокументацияпонять, как работает этот метод.
fn main() {
let matches = App::new("kt")
.version("0.1.0")
.author("Jérémie Veillet. jeremie@example.com")
.about("A drop in cat replacement written in Rust")
.arg(Arg::with_name("FILE")
.help("File to print.")
.empty_values(false)
)
.get_matches();
if let Some(file) = matches.value_of("FILE") {
println!("Value for file argument: {}", file);
}
}
На этом этапе вы можете запустить приложение и передать в качестве параметра случайную строку, которая будет отображаться в вашей консоли.
$ cargo run -- test.txt
Finished dev [unoptimized + debuginfo] target(s) in 0.02s
Running `target/debug/kt test.txt`
Value for file argument: test.txt
Обратите внимание, что в настоящее время мы фактически не проверяем существование этого файла. Итак, как мы должны этого достичь?
Существует стандартная библиотека, которая позволяет нам проверить, существует ли файл или каталог, и она очень проста в использовании. этоstd::path
библиотека. оно имеетexists
метод, который может помочь нам проверить, существует ли файл.
Как упоминалось ранее, используйтеuse
ключевое слово, чтобы добавить зависимые библиотеки, а затем напишите следующий код. Вы можете видеть, что мы используемIf-Else
Условный элемент управления печатает некоторый текст на выходе.println!
метод пишет в стандартный выводstdout
,иeprintln!
будет писать в стандартный вывод ошибокstderr
.
extern crate clap;
use clap::{Arg, App};
use std::path::Path;
use std::process;
fn main() {
let matches = App::new("kt")
.version("0.1.0")
.author("Jérémie Veillet. jeremie@example.com")
.about("A drop in cat replacement written in Rust")
.arg(Arg::with_name("FILE")
.help("File to print.")
.empty_values(false)
)
.get_matches();
if let Some(file) = matches.value_of("FILE") {
println!("Value for file argument: {}", file);
if Path::new(&file).exists() {
println!("File exist!!");
}
else {
eprintln!("[kt Error] No such file or directory.");
process::exit(1); // 程序错误终止时的标准退出码
}
}
}
Мы почти закончили! Теперь нам нужно прочитать содержимое файла и отобразить результат вstdout
середина.
Точно так же мы будем использоватьFile
Стандартная библиотека для чтения файлов. мы будем использоватьopen
метод, чтобы прочитать содержимое файла, а затем записать его в строковый объект, который будетstdout
отображается в.
extern crate clap;
use clap::{Arg, App};
use std::path::Path;
use std::process;
use std::fs::File;
use std::io::{Read};
fn main() {
let matches = App::new("kt")
.version("0.1.0")
.author("Jérémie Veillet. jeremie@example.com")
.about("A drop in cat replacement written in Rust")
.arg(Arg::with_name("FILE")
.help("File to print.")
.empty_values(false)
)
.get_matches();
if let Some(file) = matches.value_of("FILE") {
if Path::new(&file).exists() {
println!("File exist!!");
let mut f = File::open(file).expect("[kt Error] File not found.");
let mut data = String::new();
f.read_to_string(&mut data).expect("[kt Error] Unable to read the file.");
println!("{}", data);
}
else {
eprintln!("[kt Error] No such file or directory.");
process::exit(1);
}
}
}
Соберите и снова запустите этот код. Поздравляем! Теперь у нас есть полнофункциональный инструмент! 🍾
$ cargo build
Compiling kt v0.1.0 (/home/jeremie/Development/kt)
Finished dev [unoptimized + debuginfo] target(s) in 0.70s
$ cargo run -- ./src/main.rs
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Running `target/debug/kt ./src/main.rs`
File exist!!
extern crate clap;
use clap::{Arg, App};
use std::path::Path;
use std::process;
use std::fs::File;
use std::io::{Read};
fn main() {
let matches = App::new("kt")
.version("0.1.0")
.author("Jérémie Veillet. jeremie@example.com")
.about("A drop in cat replacement written in Rust")
.arg(Arg::with_name("FILE")
.help("File to print.")
.empty_values(false)
)
.get_matches();
if let Some(file) = matches.value_of("FILE") {
if Path::new(&file).exists() {
println!("File exist!!");
let mut f = File::open(file).expect("[kt Error] File not found.");
let mut data = String::new();
f.read_to_string(&mut data).expect("[kt Error] Unable to read the file.");
println!("{}", data);
}
else {
eprintln!("[kt Error] No such file or directory.");
process::exit(1);
}
}
}
немного улучшить
Теперь наше приложение может получать параметр иstdout
результаты отображаются в.
Мы можем немного настроить производительность всей фазы печати, используяwriteln!
заменитьprintln!
. это вУчебник по выводу RustЕсть хорошее объяснение. Попутно мы можем подчистить код, удалить ненужную печать и настроить возможные сценарии ошибок.
extern crate clap;
use clap::{Arg, App};
use std::path::Path;
use std::process;
use std::fs::File;
use std::io::{Read, Write};
fn main() {
let matches = App::new("kt")
.version("0.1.0")
.author("Jérémie Veillet. jeremie@example.com")
.about("A drop in cat replacement written in Rust")
.arg(Arg::with_name("FILE")
.help("File to print.")
.empty_values(false)
)
.get_matches();
if let Some(file) = matches.value_of("FILE") {
if Path::new(&file).exists() {
match File::open(file) {
Ok(mut f) => {
let mut data = String::new();
f.read_to_string(&mut data).expect("[kt Error] Unable to read the file.");
let stdout = std::io::stdout(); // 获取全局 stdout 对象
let mut handle = std::io::BufWriter::new(stdout); // 可选项:将 handle 包装在缓冲区中
match writeln!(handle, "{}", data) {
Ok(_res) => {},
Err(err) => {
eprintln!("[kt Error] Unable to display the file contents. {:?}", err);
process::exit(1);
},
}
}
Err(err) => {
eprintln!("[kt Error] Unable to read the file. {:?}", err);
process::exit(1);
},
}
}
else {
eprintln!("[kt Error] No such file or directory.");
process::exit(1);
}
}
}
$ cargo run -- ./src/main.rs
Finished dev [unoptimized + debuginfo] target(s) in 0.02s
Running `target/debug/kt ./src/main.rs`
extern crate clap;
use clap::{Arg, App};
use std::path::Path;
use std::process;
use std::fs::File;
use std::io::{Read, Write};
fn main() {
let matches = App::new("kt")
.version("0.1.0")
.author("Jérémie Veillet. jeremie@example.com")
.about("A drop in cat replacement written in Rust")
.arg(Arg::with_name("FILE")
.help("File to print.")
.empty_values(false)
)
.get_matches();
if let Some(file) = matches.value_of("FILE") {
if Path::new(&file).exists() {
match File::open(file) {
Ok(mut f) => {
let mut data = String::new();
f.read_to_string(&mut data).expect("[kt Error] Unable to read the file.");
let stdout = std::io::stdout(); // 获取全局 stdout 对象
let mut handle = std::io::BufWriter::new(stdout); // 可选项:将 handle 包装在缓冲区中
match writeln!(handle, "{}", data) {
Ok(_res) => {},
Err(err) => {
eprintln!("[kt Error] Unable to display the file contents. {:?}", err);
process::exit(1);
},
}
}
Err(err) => {
eprintln!("[kt Error] Unable to read the file. {:?}", err);
process::exit(1);
},
}
}
else {
eprintln!("[kt Error] No such file or directory.");
process::exit(1);
}
}
}
Мы сделали! Мы закончили нашу упрощенную версию всего за 45 строк кода.cat
команда 🤡, и она работает очень хорошо!
Создавайте автономные приложения
Так что же нужно, чтобы собрать это приложение и установить его в файловую систему? Попроси груз о помощи!
cargo build
принять один---release
флаги, чтобы мы могли указать окончательную версию исполняемого файла, который нам нужен.
$ cargo build --release
Compiling libc v0.2.48
Compiling unicode-width v0.1.5
Compiling ansi_term v0.11.0
Compiling bitflags v1.0.4
Compiling vec_map v0.8.1
Compiling strsim v0.7.0
Compiling textwrap v0.10.0
Compiling atty v0.2.11
Compiling clap v2.32.0
Compiling kt v0.1.0 (/home/jeremie/Development/kt)
Finished release [optimized] target(s) in 28.17s
Полученный исполняемый файл находится в этом подкаталоге:./target/release/kt
.
Вы можете скопировать этот файл на свойPATH
переменные среды или используйте команду cargo для его автоматической установки. Приложение будет установлено в~/.cargo/bin/
каталог (убедитесь, что каталог находится в~/.bashrc
или~/.zshrc
изPATH
переменные окружения).
$ cargo install --path .
Installing kt v0.1.0 (/home/jeremie/Development/kt)
Finished release [optimized] target(s) in 0.03s
Installing /home/jeremie/.cargo/bin/kt
Теперь мы можем использовать прямо в терминалеkt
Команда вызывает наше приложение! \о/
$ kt -V
kt 0.1.0
Суммировать
Мы создали гаджет командной строки всего из нескольких строк кода на Rust, который принимает путь к файлу в качестве входных данных иstdout
для отображения содержимого файла.
вы можете найти это в этомРепозиторий GitHubНайдите весь исходный код в этой статье.
Ваша очередь улучшить этот инструмент!
- Вы можете добавить параметр командной строки, чтобы контролировать, добавляются ли номера строк к выходным данным (
-n
вариант). - чтобы отобразить только часть файла, то нажатием на клавиатуре
ENTER
клавишу для отображения остальных. - использовать
kt myfile.txt myfile2.txt myfile3.txt
Такой синтаксис открывает сразу несколько файлов.
Не стесняйтесь сказать мне, что вы сделали с ним! 😎
Особая благодарность Анаис, которая помогла отредактировать эту статью.👍
Узнайте больше
- cat: страница Википедии для утилиты cat.
- kt-rs
- Rust Cookbook
- Clap: полнофункциональный высокопроизводительный анализатор аргументов командной строки Rust.
- Reqwest: простой, но мощный HTTP-клиент для Rust.
- Serde: Фреймворк сериализации для Rust.
- crates.io: сайт регистрации инструментов для сообщества Rust.
Если вы обнаружите ошибки в переводе или в других областях, требующих доработки, добро пожаловать наПрограмма перевода самородковВы также можете получить соответствующие бонусные баллы за доработку перевода и PR. начало статьиПостоянная ссылка на эту статьюЭто ссылка MarkDown этой статьи на GitHub.
Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из ИнтернетаНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,продукт,дизайн,искусственный интеллектЕсли вы хотите видеть более качественные переводы, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.