Введение
Rust — это язык системного программирования, который сочетает производительность C++ с безопасностью памяти, предотвращая целые классы уязвимостей. Согласно отчёту Stack Overflow Developer Survey 2025, Rust уже восьмой год подряд занимает первое место среди «самых любимых» языков программирования. Его экосистема активно растёт: от CLI-утилит (ripgrep, fd, bat) до WebAssembly-фреймворков (Yew, Dioxus, Leptos).
Однако даже опытные разработчики тратят до 40% времени на рутинные задачи: написание безопасного unsafe-кода, парсинг конфигураций, генерацию бойлерплейта для WASM. Современные языковые модели, такие как GPT-4o и Claude 3.5 Sonnet, способны ускорить эти процессы, если правильно формулировать запросы.
В этой подборке — 15 конкретных промтов, которые помогут вам:
- Писать безопасный и идиоматичный код на Rust
- Создавать CLI-утилиты с нуля
- Работать с WebAssembly (WASM) и парсить данные
Каждый промт готов к копированию. Указывайте свою версию Rust (проверьте через rustc --version) — примеры рассчитаны на стабильный релиз 1.85+ (июль 2026).
1. Генерация безопасного кода с нулевой стоимостью абстракций
Для чего: Создать идиоматичный Rust-код с использованием трейтов, дженериков и владения без утечек.
Промт:
Ты — эксперт по Rust с 10-летним опытом. Напиши функцию на Rust, которая:
- принимает замыкание и список чисел
- применяет замыкание к каждому элементу, возвращая новый вектор
- использует нулевые абстракции (zero-cost abstractions)
- включает аннотации lifetimes, если необходимо
- не использует unsafe код
Добавь комментарии с объяснением каждого шага. Версия Rust: 1.85.
Пример использования:
fn map_with_closure<T, F>(data: &[T], mut f: F) -> Vec<T>
where
T: Clone,
F: FnMut(&T) -> T,
{
data.iter().map(
|x| f(x)).collect()
}
fn main() {
let numbers = vec![1, 2, 3];
let doubled = map_with_closure(&numbers,
|x| x * 2);
println!("{:?}", doubled); // [2, 4, 6]
}
Почему это работает: Промт задаёт конкретные требования (lifetimes, zero-cost), что заставляет модель генерировать код с явными аннотациями и избегать клонирования без необходимости. Результат можно сразу вставить в main.rs.
2. Рефакторинг unsafe-кода в безопасный
Для чего: Преобразовать существующий код с unsafe в безопасный аналог с использованием std::cell, RefCell или Mutex.
Промт:
У меня есть код на Rust, который использует unsafe для модификации статической переменной:
static mut COUNTER: u32 = 0;
unsafe {
COUNTER += 1;
}
Перепиши его без unsafe, используя std::sync::atomic или std::cell::Cell. Объясни, почему твой вариант безопаснее. Версия Rust: 1.85.
Пример использования:
use std::sync::atomic::{AtomicU32, Ordering};
static COUNTER: AtomicU32 = AtomicU32::new(0);
fn increment() {
COUNTER.fetch_add(1, Ordering::SeqCst);
}
fn main() {
increment();
println!("{}", COUNTER.load(Ordering::SeqCst)); // 1
}
Почему это работает: Промт явно указывает проблему (unsafe для статической переменной) и просит альтернативу. Модель предлагает AtomicU32 — правильный выбор для многопоточности, что предотвращает data races.
3. Создание CLI-утилиты с clap и anyhow
Для чего: Быстро сгенерировать скелет CLI-приложения с парсингом аргументов и обработкой ошибок.
Промт:
Напиши полный код CLI-утилиты на Rust, которая:
- использует крейты clap 4.x и anyhow
- принимает флаг --verbose (bool) и аргумент --input (строка)
- читает файл по указанному пути и выводит количество строк
- обрабатывает ошибки (файл не найден, нет прав) с помощью anyhow
- имеет версию и описание
Выведи только код. Версия Rust: 1.85.
Пример использования:
use clap::Parser;
use anyhow::{Context, Result};
use std::fs;
#[derive(Parser)]
#[command(name = "line-counter")]
#[command(about = "Count lines in a file", long_about = None)]
struct Cli {
#[arg(short, long, default_value_t = false)]
verbose: bool,
#[arg(short, long)]
input: String,
}
fn main() -> Result<()> {
let cli = Cli::parse();
let content = fs::read_to_string(&cli.input)
.with_context(|| format!("Failed to read file: {}", cli.input))?;
let line_count = content.lines().count();
if cli.verbose {
println!("File: {}, Lines: {}", cli.input, line_count);
} else {
println!("{}", line_count);
}
Ok(())
}
Почему это работает: Промт использует популярные крейты (clap — де-факто стандарт для CLI, anyhow — для простой обработки ошибок). Код готов к запуску после добавления зависимостей в Cargo.toml.
4. Парсинг CSV с serde
Для чего: Прочитать CSV-файл с заголовками и десериализовать его в структуры.
Промт:
Напиши Rust-программу, которая:
- использует крейты csv 1.x и serde (Serialize, Deserialize)
- определяет структуру с полями: name (String), age (u32), email (String)
- читает CSV-файл "data.csv" с заголовками
- выводит всех пользователей старше 18 лет
- обрабатывает ошибки через anyhow
Выведи только код. Версия Rust: 1.85.
Пример использования:
use serde::Deserialize;
use anyhow::Result;
#[derive(Debug, Deserialize)]
struct User {
name: String,
age: u32,
email: String,
}
fn main() -> Result<()> {
let mut rdr = csv::Reader::from_path("data.csv")?;
for result in rdr.deserialize() {
let user: User = result?;
if user.age > 18 {
println!("{} ({}) - {}", user.name, user.age, user.email);
}
}
Ok(())
}
Почему это работает: Serde — стандартная библиотека сериализации в Rust. Промт чётко описывает структуру данных и фильтр, что позволяет модели сгенерировать рабочий код без лишнего бойлерплейта.
5. Оптимизация по памяти с помощью аллокаторов
Для чего: Написать код, который использует кастомный аллокатор (например, jemalloc) для снижения фрагментации памяти.
Промт:
Напиши пример на Rust, который:
- использует крейт jemallocator (версия 0.5+)
- создаёт вектор из 1_000_000 элементов типа u64
- замеряет время выполнения и пиковое потребление памяти через std::time::Instant
- сравнивает с глобальным аллокатором (std::alloc::System)
Выведи код с комментариями. Версия Rust: 1.85.
Пример использования:
use std::time::Instant;
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
fn main() {
let start = Instant::now();
let data: Vec<u64> = (0..1_000_000).collect();
let duration = start.elapsed();
println!("Time: {:?}, Len: {}", duration, data.len());
}
Почему это работает: Промт фокусируется на конкретной оптимизации (jemalloc) и добавляет метрики. Это полезно для системного программирования, где важна производительность.
6. Генерация WebAssembly-модуля
Для чего: Создать WASM-модуль на Rust, который можно вызвать из JavaScript.
Промт:
Напиши Rust-код для WebAssembly, который:
- использует wasm-bindgen 0.2.x
- экспортирует функцию add(a: i32, b: i32) -> i32
- не использует std (no_std)
- компилируется в wasm32-unknown-unknown
- включает комментарии с инструкцией по сборке (wasm-pack build --target web)
Выведи только код. Версия Rust: 1.85.
Пример использования:
#![no_std]
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
Почему это работает: no_std гарантирует, что модуль будет лёгким. Промт явно указывает цель (wasm32-unknown-unknown) и инструмент сборки (wasm-pack), что устраняет двусмысленность.
7. Парсинг JSON с вложенными структурами
Для чего: Разобрать сложный JSON с вложенными объектами и массивами.
Промт:
Напиши Rust-программу, которая:
- использует serde_json 1.x
- определяет структуры для JSON вида:
{
"users": [
{
"id": 1,
"name": "Alice",
"address": {
"city": "Moscow",
"zip": "101000"
}
}
]
}
- выводит имена пользователей и их города
- обрабатывает ошибки через unwrap_or_else
Выведи только код. Версия Rust: 1.85.
Пример использования:
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Address {
city: String,
zip: String,
}
#[derive(Debug, Deserialize)]
struct User {
id: u32,
name: String,
address: Address,
}
#[derive(Debug, Deserialize)]
struct Data {
users: Vec<User>,
}
fn main() {
let json_str = r#"{"users":[{"id":1,"name":"Alice","address":{"city":"Moscow","zip":"101000"}}]}"#;
let data: Data = serde_json::from_str(json_str).unwrap_or_else(
|e| {
eprintln!("Parse error: {}", e);
std::process::exit(1);
});
for user in &data.users {
println!("{} lives in {}", user.name, user.address.city);
}
}
Почему это работает: Промт даёт конкретный пример JSON, что исключает разночтения. Вложенные структуры требуют явного определения типов — модель генерирует их автоматически.
8. Работа с многопоточностью через Rayon
Для чего: Параллельно обработать большой массив данных.
Промт:
Напиши Rust-программу, которая:
- использует крейт rayon 1.9+
- создаёт вектор из 10_000_000 чисел
- параллельно вычисляет квадрат каждого числа через par_iter
- замеряет время выполнения по сравнению с последовательным iter
- выводит оба времени
Выведи только код. Версия Rust: 1.85.
Пример использования:
use rayon::prelude::*;
use std::time::Instant;
fn main() {
let data: Vec<u64> = (0..10_000_000).collect();
let start = Instant::now();
let _sequential: Vec<u64> = data.iter().map(
|x| x * x).collect();
let seq_time = start.elapsed();
let start = Instant::now();
let _parallel: Vec<u64> = data.par_iter().map(
|x| x * x).collect();
let par_time = start.elapsed();
println!("Sequential: {:?}, Parallel: {:?}", seq_time, par_time);
}
Почему это работает: Rayon — стандарт для параллельных вычислений в Rust. Промт просит сравнение с последовательным кодом, что даёт наглядную демонстрацию ускорения.
9. Создание кастомного итератора
Для чего: Реализовать трейт Iterator для пользовательской структуры.
Промт:
Напиши Rust-код, который:
- определяет структуру Fibonacci с полями a и b (тип u128)
- реализует трейт Iterator для Fibonacci, генерируя бесконечную последовательность Фибоначчи
- в main выводит первые 20 чисел через take(20)
- использует impl Iterator
Выведи только код. Версия Rust: 1.85.
Пример использования:
struct Fibonacci {
a: u128,
b: u128,
}
impl Fibonacci {
fn new() -> Self {
Fibonacci { a: 0, b: 1 }
}
}
impl Iterator for Fibonacci {
type Item = u128;
fn next(&mut self) -> Option<Self::Item> {
let current = self.a;
self.a = self.b;
self.b = current + self.b;
Some(current)
}
}
fn main() {
for (i, val) in Fibonacci::new().take(20).enumerate() {
println!("F{}: {}", i, val);
}
}
Почему это работает: Реализация итераторов — частая задача в Rust. Промт чётко указывает тип (u128) и метод (take), что предотвращает переполнение.
10. Интеграция с C через FFI
Для чего: Вызвать C-функцию из Rust с помощью extern "C".
Промт:
Напиши Rust-программу, которая:
- объявляет внешнюю C-функцию: double sqrt(double x) из libm
- вызывает её через unsafe и extern "C"
- выводит результат для x = 2.0
- использует std::os::raw::c_double
Выведи только код. Версия Rust: 1.85.
Пример использования:
use std::os::raw::c_double;
extern "C" {
fn sqrt(x: c_double) -> c_double;
}
fn main() {
let x: c_double = 2.0;
unsafe {
let result = sqrt(x);
println!("sqrt({}) = {}", x, result);
}
}
Почему это работает: Промт использует стандартную C-библиотеку (libm), которая доступна на всех платформах. Это безопасный пример FFI без сторонних зависимостей.
11. Работа с большими файлами через mmap
Для чего: Отобразить файл в память для быстрого чтения без копирования.
Промт:
Напиши Rust-программу, которая:
- использует крейт memmap2 0.9+
- открывает файл "large.bin" (если не существует, создаёт с 1_000_000 байт)
- отображает его в память через Mmap
- читает первые 100 байт и выводит их как срез
- обрабатывает ошибки через anyhow
Выведи только код. Версия Rust: 1.85.
Пример использования:
use memmap2::Mmap;
use std::fs::File;
use anyhow::Result;
fn main() -> Result<()> {
let file = File::open("large.bin")?;
let mmap = unsafe { Mmap::map(&file)? };
let first_hundred = &mmap[..100.min(mmap.len())];
println!("First 100 bytes: {:?}", first_hundred);
Ok(())
}
Почему это работает: memmap2 — популярная библиотека для работы с mmap. Промт включает создание файла для теста, что делает пример самодостаточным.
12. Генерация документации с примерами
Для чего: Создать doc-комментарии с примерами кода, которые будут тестироваться через cargo test.
Промт:
Напиши функцию на Rust с именем factorial(n: u64) -> u64, которая:
- вычисляет факториал рекурсивно
- содержит doc-комментарии с описанием, аргументами, паникой (если n > 20)
- включает секцию ```rust с примером использования, который будет работать как doctest
- использует #[must_use]
Выведи только код. Версия Rust: 1.85.
Пример использования:
/// Вычисляет факториал числа n.
///
/// # Arguments
/// * `n` - Неотрицательное целое число (до 20, чтобы избежать переполнения u64)
///
/// # Panics
/// Паникует, если n > 20, так как результат не помещается в u64.
///
/// # Examples
/// ```
/// let result = factorial(5);
/// assert_eq!(result, 120);
/// ```
#[must_use]
pub fn factorial(n: u64) -> u64 {
if n > 20 {
panic!("n must be <= 20");
}
match n {
0 | 1 => 1,
_ => n * factorial(n - 1),
}
}
Почему это работает: Doc-тесты — встроенная возможность Rust. Промт просит #[must_use] и ограничение на n, что делает код надёжным.
13. Оптимизация с помощью профилирования
Для чего: Добавить инструменты профилирования (CPU, память) в программу.
Промт:
Напиши Rust-программу, которая:
- использует крейт cpuprofiler 0.1+ для профилирования CPU
- создаёт цикл из 1_000_000 итераций с вычислением синуса
- запускает профилировщик на время цикла
- выводит сообщение "Profiling done" после остановки
Выведи только код. Версия Rust: 1.85.
Пример использования:
use cpuprofiler::PROFILER;
fn main() {
PROFILER.lock().unwrap().start("./profile.prof").unwrap();
for i in 0..1_000_000 {
let _ = (i as f64).sin();
}
PROFILER.lock().unwrap().stop().unwrap();
println!("Profiling done");
}
Почему это работает: Профилирование — ключевой навык в системном программировании. Промт использует простой крейт, который генерирует файл для pprof.
14. Работа с асинхронностью через Tokio
Для чего: Написать асинхронный HTTP-клиент, который выполняет несколько запросов параллельно.
Промт:
Напиши Rust-программу, которая:
- использует tokio 1.x и reqwest 0.12+
- создаёт список URL: ["https://httpbin.org/delay/1", "https://httpbin.org/delay/2"]
- выполняет GET-запросы параллельно через tokio::join!
- выводит статус-коды и длину тела
- использует #[tokio::main]
Выведи только код. Версия Rust: 1.85.
Пример использования:
use reqwest::Client;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
let urls = vec![
"https://httpbin.org/delay/1",
"https://httpbin.org/delay/2",
];
let responses = futures::future::join_all(urls.iter().map(
|url| client.get(*url).send())).await;
for (i, resp) in responses.iter().enumerate() {
match resp {
Ok(r) => println!("URL {}: status {}, body len {}", i, r.status(), r.content_length().unwrap_or(0)),
Err(e) => eprintln!("URL {}: error {}", i, e),
}
}
Ok(())
}
Почему это работает: Tokio — стандартный асинхронный рантайм. Промт использует join_all для параллелизации, что экономит время.
15. Парсинг аргументов командной строки вручную
Для чего: Разобрать аргументы без крейтов, используя std::env::args.
Промт:
Напиши Rust-программу, которая:
- получает аргументы через std::env::args()
- если передан --help, выводит справку
- если передан --name <value>, выводит "Hello, <value>!"
- иначе выводит "Usage: ..."
- не использует сторонние крейты
Выведи только код. Версия Rust: 1.85.
Пример использования:
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
match args.as_slice() {
[_, flag, value] if flag == "--name" => println!("Hello, {}!", value),
[_, flag] if flag == "--help" => println!("Usage: program --name <name>"),
_ => println!("Usage: program --name <name>"),
}
}
Почему это работает: Промт учит работе с сырыми аргументами — полезно для минималистичных утилит или когда не хочется подключать clap.
Заключение
Мы разобрали 15 промтов, покрывающих ключевые области Rust: от системного программирования (FFI, mmap, профилирование) до практических утилит (CLI, парсинг, асинхронность). Каждый промт можно адаптировать под свой проект — меняйте типы, названия или добавляйте условия.
Чтобы получить максимальную пользу:
1. Указывайте версию Rust — это предотвращает устаревшие конструкции.
2. Добавляйте конкретные примеры входных данных — модель даст точный код.
3. Тестируйте результат через cargo check — многие ошибки отлавливаются на этапе компиляции.
Попробуйте применить эти промты в своём следующем проекте: CLI-утилите, WASM-модуле или высоконагруженном сервере. Rust — это язык, где правильный промт экономит часы отладки.
Комментарии