Простые приложения на Rust
Простые приложения на Rust
Rust подходит для надёжных утилит: компилятор ловит ошибки владения до запуска, cargo собирает бинарник и тесты. Примеры ниже — на стандартной библиотеке; для HTTP в продакшене чаще берут Axum, но для старта достаточно понять Result, match и работу с файлами.
Порядок: после первой программы и типов с владением.
Как запускать примеры из главы
- Для примеров с
rand/serde:cargo new demo && cd demo, вставьте код вsrc/main.rs, добавьте зависимости вCargo.toml. - Команда:
cargo run - Один файл без Cargo:
rustc src/main.rs && ./main(Linux/macOS) илиmain.exe(Windows).
Проверка: rustc --version, cargo --version.
Генератор паролей
Как запустить
- Проект:
cargo new password && cd password - Cargo.toml:
rand = "0.8" - Команда:
cargo run - Результат: одна строка — пароль из 16 символов.
use rand::Rng;
use rand::seq::SliceRandom;
fn generate_password(len: usize) -> String {
const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%";
let mut rng = rand::thread_rng();
(0..len)
.map(|_| CHARSET[rng.gen_range(0..CHARSET.len())] as char)
.collect()
}
fn main() {
println!("{}", generate_password(16));
}
В Cargo.toml: rand = "0.8". Для паролей в продакшене предпочтительнее rand с OsRng / crate getrandom.
Сортировщик текстового файла
Как запустить
- Файл:
src/main.rsв проектеcargo new sort_file - Подготовка:
input.txtв корне проекта; путь вsort_file(...). - Команда:
cargo run - Результат:
output.txtс отсортированными строками.
use std::fs;
use std::io;
fn sort_file(input: &str, output: &str) -> io::Result<()> {
let mut lines: Vec<String> = fs::read_to_string(input)?
.lines()
.map(str::trim)
.filter(|s| !s.is_empty())
.map(String::from)
.collect();
lines.sort();
fs::write(output, lines.join("\n") + "\n")?;
Ok(())
}
Разбор: ? пробрасывает io::Error; владение строк переходит в Vec без лишних копий там, где достаточно &str при чтении.
Консольный калькулятор
Как запустить
- Команда:
cargo run(проект с этимmain) - Нужно: терминал; ввод вида
10 + 3или по строкам — как в коде. - Результат:
= 13.0или сообщение об ошибке.
use std::io::{self, Write};
fn calc(a: f64, b: f64, op: char) -> Result<f64, String> {
Ok(match op {
'+' => a + b,
'-' => a - b,
'*' => a * b,
'/' if b == 0.0 => return Err("деление на ноль".into()),
'/' => a / b,
_ => return Err(format!("неизвестный оператор: {op}")),
})
}
fn main() -> io::Result<()> {
let stdin = io::stdin();
loop {
print!("a op b (q): ");
io::stdout().flush()?;
let mut line = String::new();
stdin.read_line(&mut line)?;
let line = line.trim();
if line == "q" { break; }
let mut parts = line.split_whitespace();
let a: f64 = parts.next().ok_or("a?")?.parse().map_err(|_| "a?")?;
let op = parts.next().ok_or("op?")?.chars().next().ok_or("op?")?;
let b: f64 = parts.next().ok_or("b?")?.parse().map_err(|_| "b?")?;
match calc(a, b, op) {
Ok(v) => println!("= {v}"),
Err(e) => eprintln!("{e}"),
}
}
Ok(())
}
Трекер задач в JSON (serde)
Как запустить
- Cargo.toml:
serde = { version = "1", features = ["derive"] },serde_json = "1" - Команда:
cargo run - Результат: файл
tasks.jsonв каталоге проекта.
use serde::{Deserialize, Serialize};
use std::fs;
#[derive(Debug, Serialize, Deserialize)]
struct Task {
id: u64,
title: String,
done: bool,
}
const DB: &str = "tasks.json";
fn load() -> Vec<Task> {
fs::read_to_string(DB)
.ok()
.and_then(|s| serde_json::from_str(&s).ok())
.unwrap_or_default()
}
fn save(tasks: &[Task]) -> std::io::Result<()> {
fs::write(DB, serde_json::to_string_pretty(tasks)?)
}
fn main() -> std::io::Result<()> {
let mut tasks = load();
tasks.push(Task {
id: 1,
title: "Изучить Rust".into(),
done: false,
});
save(&tasks)?;
Ok(())
}
Cargo.toml: serde = { version = "1", features = ["derive"] }, serde_json = "1".
Минимальный HTTP-сервер (hyper / tiny_http альтернатива — std через TcpListener)
Как запустить
- Команда:
cargo run - Проверка: в другом терминале
curl http://127.0.0.1:3000/— JSON в ответе. - Остановка:
Ctrl+C.
use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
fn handle(mut stream: TcpStream) -> std::io::Result<()> {
let mut buf = [0u8; 1024];
let n = stream.read(&mut buf)?;
let req = String::from_utf8_lossy(&buf[..n]);
let body = r#"{"ok":true}"#;
let response = format!(
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{}",
body.len(),
body
);
stream.write_all(response.as_bytes())
}
fn main() -> std::io::Result<()> {
let listener = TcpListener::bind("127.0.0.1:3000")?;
for stream in listener.incoming().flatten() {
let _ = handle(stream);
}
Ok(())
}
Для учебного API дальше переходите на Axum.
Обход каталога
Как запустить
- Команда:
cargo runиз каталога, который нужно сканировать (измените путь вscan(...)). - Результат: кортеж
(число_файлов, байты).
use std::fs;
use std::path::Path;
fn scan(dir: &Path, ext: &str) -> std::io::Result<(usize, u64)> {
let mut files = 0usize;
let mut bytes = 0u64;
for entry in fs::read_dir(dir)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
let (f, b) = scan(&path, ext)?;
files += f;
bytes += b;
} else if path.extension().and_then(|e| e.to_str()) == Some(ext.trim_start_matches('.')) {
files += 1;
bytes += entry.metadata()?.len();
}
}
Ok((files, bytes))
}
Характерный пример для Rust — Result и match
Как запустить
- Команда:
cargo runилиrustc main.rs && ./main - Результат: для
8080—8080; дляabcи0— сообщения об ошибке.
fn parse_port(s: &str) -> Result<u16, String> {
let port: u16 = s.parse().map_err(|_| "порт должен быть числом".to_string())?;
if port == 0 {
return Err("порт не может быть 0".into());
}
Ok(port)
}
fn main() {
for input in ["8080", "abc", "0"] {
match parse_port(input) {
Ok(p) => println!("{input} → {p}"),
Err(e) => println!("{input}: {e}"),
}
}
}
Ошибки — часть сигнатуры; это отличает Rust от языков с исключениями «на всё».
См. также
Другие статьи этого же раздела в боковом меню (как на странице «О разделе»). История Rust - путь языка от эксперимента до промышленного стандарта безопасного системного программирования. Rust — это многопарадигменный язык программирования общего назначения, который фокусируется на безопасности памяти, производительности и параллелизме. Набор советов, правил, принципов и обычаев в разработке на этом языке. Трейты могут иметь методы по умолчанию. Если тип не переопределяет метод, используется версия из трейта. Это позволяет расширять функциональность без изменения базового кода. fn - ключевое слово, которое обозначает начало объявления функции. Функция представляет собой именованный блок кода, выполняющий конкретную задачу. В данном случае функция называется main. Экосистема приложений на Rust - направления применения языка и ключевые инструменты промышленной разработки. Системное программирование на Rust - низкоуровневый контроль, безопасность памяти и надёжные инфраструктурные компоненты. Кавычки, точки, запятые, скобки и прочие знаки препинания. Ключевые слова Rust - назначение операторов и зарезервированных идентификаторов в синтаксисе языка. Встроенные функции и стандартная библиотека Rust - базовые макросы, атрибуты и инструменты тестирования. Типизация, набор правил определения типа данных значений языка. Управляющие конструкции и циклы в Rust - `if`, `match`, `loop/while/for` и контроль потоков с акцентом на безопасность.История языка Rust
Что требуется знать перед началом изучения языка программирования Rust
Рекомендации по разработке на Rust
Rust для начинающих
Основы языка Rust
Экосистема приложений на Rust
Системное программирование на Rust
Синтаксис и пунктуация в Rust
Ключевые слова языка Rust
Встроенные функции и стандартная библиотека
Типы данных и владение памятью
Управляющие конструкции и циклы в Rust