
Rust Best Practices
- 80 installs
- 253 repo stars
- Updated August 4, 2026
- majiayu000/claude-arsenal
Helps with ai & agent building tasks during AI-assisted development.
About
rust-best-practices is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- rust-best-practices
- AI & Agent Building
- AI-coding skill
Rust Best Practices by the numbers
- 80 all-time installs (skills.sh)
- Ranked #5,257 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/majiayu000/claude-arsenal --skill rust-best-practicesAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 80 |
|---|---|
| repo stars | ★ 253 |
| Last updated | August 4, 2026 |
| Repository | majiayu000/claude-arsenal ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Rust Best Practices
Based on Microsoft Pragmatic Rust Guidelines and Rust community standards.
Core Principles
1. Leverage the type system — Use types to make invalid states unrepresentable 2. Embrace ownership — Work with the borrow checker, not against it 3. Explicit over implicit — Be clear about fallibility, mutability, and lifetimes 4. Zero-cost abstractions — Use iterators, generics, and traits without runtime cost 5. Fail fast, recover gracefully — Validate early, handle errors explicitly
---
Error Handling
Use thiserror for Libraries
use thiserror::Error;
#[derive(Error, Debug)]
pub enum MyError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Parse error at line {line}: {message}")]
Parse { line: usize, message: String },
#[error("Not found: {0}")]
NotFound(String),
}Use anyhow for Applications
use anyhow::{Context, Result};
fn main() -> Result<()> {
let config = load_config()
.context("Failed to load configuration")?;
run_app(config)?;
Ok(())
}Never Panic in Libraries
// ❌ BAD
pub fn get_item(index: usize) -> &Item {
&self.items[index] // Panics on out-of-bounds
}
// ✅ GOOD
pub fn get_item(&self, index: usize) -> Option<&Item> {
self.items.get(index)
}
// ✅ GOOD - when you need Result
pub fn get_item(&self, index: usize) -> Result<&Item, Error> {
self.items.get(index).ok_or(Error::NotFound(index))
}---
API Design
Use Builder Pattern for Complex Configs
pub struct Client {
url: String,
timeout: Duration,
retries: u32,
}
impl Client {
pub fn builder(url: impl Into<String>) -> ClientBuilder {
ClientBuilder {
url: url.into(),
timeout: Duration::from_secs(30),
retries: 3,
}
}
}
pub struct ClientBuilder {
url: String,
timeout: Duration,
retries: u32,
}
impl ClientBuilder {
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
pub fn retries(mut self, retries: u32) -> Self {
self.retries = retries;
self
}
pub fn build(self) -> Client {
Client {
url: self.url,
timeout: self.timeout,
retries: self.retries,
}
}
}Use Newtype Pattern
// ❌ BAD - primitive obsession
fn create_user(name: String, email: String, age: u32) -> User { ... }
// ✅ GOOD - newtype wrappers
pub struct Username(String);
pub struct Email(String);
pub struct Age(u32);
impl Email {
pub fn new(email: impl Into<String>) -> Result<Self, ValidationError> {
let email = email.into();
if email.contains('@') {
Ok(Self(email))
} else {
Err(ValidationError::InvalidEmail)
}
}
}
fn create_user(name: Username, email: Email, age: Age) -> User { ... }Accept impl Trait for Flexibility
// ❌ BAD - overly specific
pub fn process(items: Vec<String>) { ... }
// ✅ GOOD - accept any iterable
pub fn process(items: impl IntoIterator<Item = impl AsRef<str>>) {
for item in items {
println!("{}", item.as_ref());
}
}---
References
- Microsoft Pragmatic Rust Guidelines
- Rust API Guidelines
- The Rust Book
- references/advanced.md — performance, async, testing, and anti-pattern examples
Advanced Rust Practices
Use this reference after the core error-handling and API-design guidance in ../SKILL.md. Keep the main skill compact; load this file when the task touches performance, async runtime behavior, test strategy, or common Rust footguns.
Performance
Avoid Unnecessary Clones
// ❌ BAD
fn process(data: &String) {
let owned = data.clone(); // Unnecessary allocation
do_something(owned);
}
// ✅ GOOD
fn process(data: &str) {
do_something(data);
}Use Cow for Conditional Ownership
use std::borrow::Cow;
fn normalize(input: &str) -> Cow<'_, str> {
if input.contains(' ') {
Cow::Owned(input.replace(' ', "_"))
} else {
Cow::Borrowed(input)
}
}Prefer Iterators Over Loops
// ❌ BAD
let mut result = Vec::new();
for item in items {
if item.is_valid() {
result.push(item.transform());
}
}
// ✅ GOOD
let result: Vec<_> = items
.into_iter()
.filter(|item| item.is_valid())
.map(|item| item.transform())
.collect();Async Patterns
Use tokio Runtime
#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::init();
run().await
}Structured Concurrency with JoinSet
use tokio::task::JoinSet;
async fn process_all(urls: Vec<String>) -> Vec<Result<Response, Error>> {
let mut set = JoinSet::new();
for url in urls {
set.spawn(async move {
fetch(&url).await
});
}
let mut results = Vec::new();
while let Some(res) = set.join_next().await {
results.push(res.unwrap());
}
results
}Use #[instrument] for Tracing
use tracing::instrument;
#[instrument(skip(password))]
async fn login(username: &str, password: &str) -> Result<Token> {
tracing::info!("Attempting login");
// ...
}Testing
Use #[test] and proptest
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
#[test]
fn test_basic() {
assert_eq!(add(2, 2), 4);
}
proptest! {
#[test]
fn test_add_commutative(a: i32, b: i32) {
prop_assert_eq!(add(a, b), add(b, a));
}
}
}Use mockall for Mocking
#[cfg_attr(test, mockall::automock)]
trait Database {
async fn get(&self, id: u64) -> Result<Record>;
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_with_mock() {
let mut mock = MockDatabase::new();
mock.expect_get()
.returning(|_| Ok(Record::default()));
let service = Service::new(mock);
assert!(service.process(1).await.is_ok());
}
}Common Anti-Patterns to Avoid
| Anti-Pattern | Better Alternative |
|---|---|
unwrap() everywhere | ? operator with proper error types |
clone() to satisfy borrow checker | Restructure code, use references |
Box<dyn Error> | Concrete error types with thiserror |
String for all text | &str, Cow<str>, or domain types |
Manual Drop for cleanup | RAII with struct destructors |
unsafe without justification | Safe abstractions first |
Arc<Mutex<_>> overuse | Message passing, channels |
| Blocking in async context | spawn_blocking for CPU work |