rust – Coding skill for AI agents
Language-specific super-code guidelines for rust.
Install the rust skill with one command
Pick the tool you use, copy the command and paste it in your terminal. The skill lands in that tool's skills folder and is ready in your next session.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/rust-39868.tgz | tar xz -C ~/.claude/skills
Call it in Claude Code: /rust – then describe the task you want done.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/rust-39868.tgz | tar xz -C ~/.codex/skills
Call it in Codex: $rust – then describe the task you want done.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/rust-39868.tgz | tar xz -C ~/.hermes/skills
Call it in Hermes Agent: /rust – then describe the task you want done.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/rust-39868.tgz | tar xz -C ~/.deepcode/skills
Call it in DeepSeek: /rust – then describe the task you want done.
SKILL.md content
Rust: Idiomatic Efficiency Reference
Apply only within the requested scope and current project conventions. Preserve behavior, ownership, error handling, accessibility and security; examples are independent fragments, not equivalent rewrites in every context. Verify language/library versions and run relevant checks. Required tests and user-facing progress/results take precedence over brevity rules. Do not install dependencies or delete files merely to follow these examples.
When to Use
- Use this skill when the task matches this description: Language-specific super-code guidelines for rust.
Table of Contents
1. [Ownership & Borrowing](#ownership)
2. [Error Handling](#errors)
3. [Iterators](#iterators)
4. [Pattern Matching](#patterns)
5. [Structs & Enums](#structs)
6. [Concurrency](#concurrency)
7. [Anti-patterns specific to Rust](#antipatterns)
---
1. Ownership & Borrowing {#ownership}
// ❌ Cloning to avoid thinking about lifetimes
fn get_name(user: &User) -> String {
user.name.clone()
}
// ✅ — return a reference when the data lives long enough
fn get_name(user: &User) -> &str {
&user.name
}// ❌ Taking ownership when borrowing suffices
fn print_name(name: String) {
println!("{name}");
}
// ✅
fn print_name(name: &str) {
println!("{name}");
}// ❌ Unnecessary .to_string() / .to_owned() in hot paths
let key = id.to_string();
map.get(&key)
// ✅ — use Borrow trait; HashMap<String, V> accepts &str as key
map.get(id)Prefer &str over String in function parameters unless the function needs to own the data.
---
2. Error Handling {#errors}
// ❌ .unwrap() in production code
let file = File::open(path).unwrap();
// ✅
let file = File::open(path)
.map_err(|e| AppError::Io { path: path.to_owned(), source: e })?;// ❌ Manual match on Result for every call
match do_thing() {
Ok(v) => v,
Err(e) => return Err(e),
}
// ✅ — the ? operator
let v = do_thing()?;// ❌ Box<dyn Error> everywhere (loses type info)
fn run() -> Result<(), Box<dyn std::error::Error>> { ... }
// ✅ — use thiserror for library errors, anyhow for application errors
use anyhow::{Context, Result};
fn run() -> Result<()> {
do_thing().context("failed during run")?;
Ok(())
}// ❌ Separate error enum variant for every call site
enum Error { FileOpen, FileRead, Parse, Network, ... }
// ✅ — use thiserror with #[from] for automatic conversion
#[derive(thiserror::Error, Debug)]
enum Error {
#[error("io error")] Io(#[from] std::io::Error),
#[error("parse error")] Parse(#[from] serde_json::Error),
}---
3. Iterators {#iterators}
// ❌ Imperative accumulation
let mut result = Vec::new();
for item in &items {
if item.active {
result.push(item.name.to_uppercase());
}
}
// ✅
let result: Vec<_> = items.iter()
.filter(|i| i.active)
.map(|i| i.name.to_uppercase())
.collect();// ❌ Manual sum
let mut total = 0;
for order in &orders { total += order.amount; }
// ✅
let total: u64 = orders.iter().map(|o| o.amount).sum();// ❌ Index-based loop
for i in 0..items.len() {
process(&items[i]);
}
// ✅
for item in &items {
process(item);
}
// With index:
for (i, item) in items.iter().enumerate() {
process(i, item);
}Chain iterators lazily; only .collect() when you actually need a concrete collection.
---
4. Pattern Matching {#patterns}
// ❌ if-let chain that should be match
if let Some(x) = opt {
if x > 0 {
process(x)
}
}
// ✅
if let Some(x) = opt.filter(|&x| x > 0) {
process(x)
}
// or match with guard:
match opt {
Some(x) if x > 0 => process(x),
_ => {}
}// ❌ match with identical arms
match status {
Status::Active => true,
Status::Pending => true,
Status::Inactive => false,
}
// ✅
matches!(status, Status::Active | Status::Pending)// ❌ Destructuring in body instead of pattern
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle(c) => { let r = c.radius; r * r * PI }
Shape::Rect(r) => { let w = r.width; let h = r.height; w * h }
}
}
// ✅ — destructure in pattern
match shape {
Shape::Circle(Circle { radius, .. }) => radius * radius * PI,
Shape::Rect(Rect { width, height }) => width * height,
}---
5. Structs & Enums {#structs}
// ❌ Enum variant carrying bool for binary state
enum State { Running(bool) } // true = paused?
// ✅ — explicit variants
enum State { Running, Paused, Stopped }// ❌ Struct with many Option fields (stringly optional)
struct Config {
timeout: Option<u64>,
retries: Option<u32>,
base_url: Option<String>,
}
// ✅ — use Default + builder pattern or #[derive(Default)] with sensible defaults
#[derive(Default)]
struct Config {
timeout: u64, // default 0 = no timeout
retries: u32, // default 0
base_url: String,
}// ❌ pub fields on a type that needs invariants
pub struct Percentage { pub value: f64 }
// ✅ — private field, constructor enforces invariant
pub struct Percentage(f64);
impl Percentage {
pub fn new(v: f64) -> Option<Self> {
(0.0..=100.0).contains(&v).then_some(Self(v))
}
}---
6. Concurrency {#concurrency}
// ❌ Arc<Mutex<T>> for read-heavy data
let data = Arc::new(Mutex::new(vec![...]));
// ✅ — RwLock for read-heavy
let data = Arc::new(RwLock::new(vec![...]));// ❌ Spawning OS threads for many small tasks
for item in items {
std::thread::spawn(|| process(item));
}
// ✅ — use rayon for CPU-bound parallel iteration
use rayon::prelude::*;
items.par_iter().for_each(|item| process(item));Use tokio::join! for scoped concurrent awaits. Spawned tasks must be awaited/cancelled deliberately: dropping a JoinHandle detaches, so spawning alone is not structured concurrency.
---
7. Anti-patterns specific to Rust {#antipatterns}
| Anti-pattern | Preferred |
|---|---|
| .clone() to appease borrow checker | reconsider lifetime or restructure |
| .unwrap() in non-test code | ? operator or explicit handling |
| impl Trait in return position hiding complex type | name the type or use Box<dyn Trait> intentionally |
| String parameter when &str suffices | &str for params, String for owned storage |
| Nested Option<Option<T>> | rethink the data model |
| unsafe block without a safety comment | always document the invariant being upheld |
| Vec<Box<T>> when Vec<T> works | avoid heap allocation inside collections unless T is unsized |
| Manual Drop for cleanup that ? handles | let RAII + ? do it |
Limitations
- These are language-specific guidelines and do not cover overall architectural decisions.
- Over-compression might reduce readability; apply judgement.
Related skills
- rust-async-patterns – Master Rust async programming with Tokio, async traits, error handling, and concurrent…
- rust-pro – Master Rust 1.75+ with modern async patterns, advanced type system features, and…
- salary-benchmarking – Salary benchmark register: role, department and grade against market and internal…
- scala – Language-specific super-code guidelines for scala.
- screen-reader-testing – Practical guide to testing web applications with screen readers for comprehensive…
- sdk-dx – Design SDKs that developers love to use—APIs that feel native, error messages that…
- selenium-skill – Generates production-grade Selenium WebDriver automation scripts and tests in Java…
- semgrep-rule-variant-creator – Creates language variants of existing Semgrep rules. Use when porting a Semgrep rule to…