Agent skill
rust-best-practices
Rust development best practices, patterns, and conventions. Use when writing Rust code, reviewing .rs files, discussing ownership, lifetimes, borrowing, or Cargo configuration. Triggers on mentions of Rust, Cargo, ownership, borrowing, lifetimes, traits, async Rust, tokio.
Install this agent skill to your Project
npx add-skill https://github.com/eous/dotclaude/tree/main/skills/rust-best-practices
SKILL.md
Rust Best Practices
Ownership and Borrowing
Prefer Borrowing Over Ownership
// Bad - takes ownership unnecessarily
fn print_name(name: String) {
println!("{}", name);
}
// Good - borrows immutably
fn print_name(name: &str) {
println!("{}", name);
}
Use References Appropriately
// Immutable borrow for reading
fn calculate_length(s: &String) -> usize {
s.len()
}
// Mutable borrow for modification
fn push_char(s: &mut String, c: char) {
s.push(c);
}
Error Handling
Use Result and Option
fn find_user(id: u32) -> Option<User> {
users.get(&id).cloned()
}
fn parse_config(path: &str) -> Result<Config, ConfigError> {
let content = fs::read_to_string(path)?;
toml::from_str(&content).map_err(ConfigError::Parse)
}
Custom Error Types
use thiserror::Error;
#[derive(Error, Debug)]
pub enum AppError {
#[error("database error: {0}")]
Database(#[from] sqlx::Error),
#[error("not found: {0}")]
NotFound(String),
#[error("validation error: {field}")]
Validation { field: String },
}
Propagate with ?
fn process_file(path: &str) -> Result<Data, Error> {
let content = fs::read_to_string(path)?;
let parsed = serde_json::from_str(&content)?;
let validated = validate(parsed)?;
Ok(validated)
}
Structs and Enums
Builder Pattern
#[derive(Default)]
pub struct ServerBuilder {
port: Option<u16>,
host: Option<String>,
}
impl ServerBuilder {
pub fn port(mut self, port: u16) -> Self {
self.port = Some(port);
self
}
pub fn host(mut self, host: impl Into<String>) -> Self {
self.host = Some(host.into());
self
}
pub fn build(self) -> Result<Server, BuildError> {
Ok(Server {
port: self.port.unwrap_or(8080),
host: self.host.unwrap_or_else(|| "localhost".into()),
})
}
}
Newtype Pattern
pub struct UserId(u64);
pub struct Email(String);
impl Email {
pub fn new(email: String) -> Result<Self, ValidationError> {
if email.contains('@') {
Ok(Self(email))
} else {
Err(ValidationError::InvalidEmail)
}
}
}
Enums for State
enum ConnectionState {
Disconnected,
Connecting { attempt: u32 },
Connected { session_id: String },
Error { message: String },
}
Traits
Implement Standard Traits
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct User {
pub id: u64,
pub name: String,
}
Trait Objects vs Generics
// Static dispatch (monomorphization)
fn process<T: Handler>(handler: T) { ... }
// Dynamic dispatch (trait object)
fn process(handler: &dyn Handler) { ... }
fn process(handler: Box<dyn Handler>) { ... }
Extension Traits
pub trait StringExt {
fn truncate_ellipsis(&self, max_len: usize) -> String;
}
impl StringExt for str {
fn truncate_ellipsis(&self, max_len: usize) -> String {
if self.len() <= max_len {
self.to_string()
} else {
format!("{}...", &self[..max_len - 3])
}
}
}
Lifetimes
Elision Rules
// Lifetimes elided - single input reference
fn first_word(s: &str) -> &str { ... }
// Explicit when multiple inputs
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { ... }
Struct Lifetimes
struct Parser<'a> {
input: &'a str,
position: usize,
}
impl<'a> Parser<'a> {
fn new(input: &'a str) -> Self {
Self { input, position: 0 }
}
}
Async Rust
Tokio Patterns
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let result = fetch_data().await?;
Ok(())
}
async fn fetch_data() -> Result<Data, Error> {
let client = reqwest::Client::new();
let response = client.get(URL).send().await?;
response.json().await.map_err(Into::into)
}
Concurrent Operations
use futures::future::join_all;
async fn fetch_all(urls: Vec<String>) -> Vec<Result<Response, Error>> {
let futures: Vec<_> = urls.into_iter()
.map(|url| fetch_one(url))
.collect();
join_all(futures).await
}
Testing
Unit Tests
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(2, 2), 4);
}
#[test]
#[should_panic(expected = "division by zero")]
fn test_divide_by_zero() {
divide(1, 0);
}
}
Integration Tests
// tests/integration_test.rs
use mylib::process;
#[test]
fn test_full_workflow() {
let result = process("input");
assert!(result.is_ok());
}
Performance
Avoid Unnecessary Allocations
// Bad - allocates new String
fn process(s: &str) -> String {
s.to_uppercase()
}
// Good when possible - use Cow
use std::borrow::Cow;
fn process(s: &str) -> Cow<str> {
if s.chars().any(|c| c.is_lowercase()) {
Cow::Owned(s.to_uppercase())
} else {
Cow::Borrowed(s)
}
}
Use Iterators
// Good - lazy, zero-cost
let sum: i32 = numbers.iter()
.filter(|n| **n > 0)
.map(|n| n * 2)
.sum();
Anti-Patterns to Avoid
.unwrap()in production code- Excessive
.clone()to "fix" borrow checker unsafewithout clear justification- Ignoring compiler warnings
- Not using
clippy - Global mutable state (
lazy_staticwithMutex)
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
typescript-best-practices
TypeScript development best practices, patterns, and conventions. Use when writing TypeScript code, reviewing .ts/.tsx files, discussing type safety, generics, utility types, or TypeScript project configuration. Triggers on mentions of TypeScript, tsconfig, type inference, generics, discriminated unions, React TypeScript.
api-design
REST and GraphQL API design patterns, best practices, and conventions. Use when designing APIs, discussing HTTP methods, status codes, versioning, or API documentation. Triggers on mentions of REST, API, GraphQL, endpoint, HTTP methods, OpenAPI, swagger, API versioning.
testing-patterns
Software testing patterns, strategies, and best practices. Use when writing tests, discussing test architecture, mocking, fixtures, or test organization. Triggers on mentions of testing, unit tests, integration tests, pytest, jest, mocking, fixtures, TDD, test coverage.
security-checklist
Application security best practices and vulnerability prevention. Use when reviewing code for security issues, implementing authentication, or discussing OWASP vulnerabilities. Triggers on mentions of security, authentication, authorization, XSS, SQL injection, CSRF, OWASP, encryption, secrets.
python-best-practices
Python development best practices, patterns, and conventions. Use when writing Python code, reviewing .py files, discussing pytest, asyncio, type hints, pydantic, dataclasses, or Python project structure. Triggers on mentions of Python, pytest, mypy, ruff, black, FastAPI, Django, Flask.
memory-generator
Generate CLAUDE.md project memory files by exploring codebases. Use when user asks to "generate memory", "create CLAUDE.md", "document this project", "understand this codebase", or starts work on a new/unfamiliar repository. Triggers on new project onboarding and documentation requests.
Didn't find tool you were looking for?