Rust-skills rust-coding
Rust coding conventions expert covering naming, formatting, comments, clippy, rustfmt, lints, code style, best practices, and idiomatic patterns.
install
source · Clone the upstream repo
git clone https://github.com/huiali/rust-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/huiali/rust-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/rust-coding" ~/.claude/skills/huiali-rust-skills-rust-coding-95f932 && rm -rf "$T"
manifest:
skills/rust-coding/SKILL.mdsource content
Naming Conventions (Rust-Specific)
| Rule | Correct | Incorrect |
|---|---|---|
No prefix for methods | | |
| Iterator methods | / / | |
| Conversion naming | (cheap), (expensive), (ownership) | Mixed usage |
variables uppercase | | |
variables | | No restriction |
General Naming
// Variables and functions: snake_case let max_connections = 100; fn process_data() { ... } // Types and traits: CamelCase struct UserSession; trait Cacheable {} // Constants: SCREAMING_SNAKE_CASE const MAX_CONNECTIONS: usize = 100; static CONFIG: once_cell::sync::Lazy<Config> = ...
Solution Patterns
Pattern 1: Conversion Methods
impl Buffer { // as_ - cheap, view conversion pub fn as_slice(&self) -> &[u8] { &self.data } // to_ - expensive, allocating conversion pub fn to_vec(&self) -> Vec<u8> { self.data.clone() } // into_ - consuming, ownership transfer pub fn into_vec(self) -> Vec<u8> { self.data } }
Pattern 2: Newtype Pattern
// ✅ Domain semantics with newtypes struct Email(String); struct UserId(u64); struct Meters(f64); impl Email { pub fn new(s: impl Into<String>) -> Result<Self, EmailError> { let email = s.into(); if email.contains('@') { Ok(Self(email)) } else { Err(EmailError::Invalid) } } }
Pattern 3: Error Handling
// ✅ Good: propagate errors fn read_config() -> Result<Config, ConfigError> { let content = std::fs::read_to_string("config.toml") .map_err(ConfigError::from)?; toml::from_str(&content) .map_err(ConfigError::Parse) } // ❌ Avoid: panic in library code fn read_config() -> Config { std::fs::read_to_string("config.toml").unwrap() // panic! } // ✅ Use expect when invariant guaranteed fn get_user(&self) -> &User { self.user.as_ref() .expect("user always initialized in constructor") }
Pattern 4: String Handling
// ✅ Accept &str in APIs fn greet(name: &str) { println!("Hello, {}", name); } // ✅ Use Cow when might need owned use std::borrow::Cow; fn process(input: &str) -> Cow<str> { if input.contains("special") { Cow::Owned(input.replace("special", "normal")) } else { Cow::Borrowed(input) } } // ✅ Pre-allocate when size known let mut s = String::with_capacity(100);
Data Type Guidelines
| Rule | Description | Example |
|---|---|---|
| Use newtype | Domain semantics | |
| Use slice patterns | Pattern matching | |
| Pre-allocate | Avoid reallocations | |
| Avoid Vec abuse | Fixed size → array | |
String Guidelines
| Rule | Description |
|---|---|
ASCII data use | faster than |
Might modify → | Borrow or owned |
Use for concat | Better than operator |
Avoid nested | O(n*m) complexity |
Error Handling Guidelines
| Rule | Description |
|---|---|
Use to propagate | Don't use macro |
over | When value guaranteed |
Use for invariants | At function entry |
Memory and Lifetimes
| Rule | Description |
|---|---|
| Meaningful lifetime names | , not just |
use | Avoid panics |
| Use shadowing for conversions | |
Concurrency Guidelines
| Rule | Description |
|---|---|
| Define lock ordering | Prevent deadlocks |
| Atomics for primitives | Not |
| Choose memory ordering carefully | Relaxed/Acquire/Release/SeqCst |
Async Guidelines
| Rule | Description |
|---|---|
| CPU-bound → sync | Async for I/O |
| Don't hold locks across await | Use scoped guards |
Macro Guidelines
| Rule | Description |
|---|---|
| Avoid macros (unless necessary) | Prefer functions/generics |
| Macro input like Rust | Readability first |
Deprecated Patterns → Modern
| Deprecated | Modern | Version |
|---|---|---|
| | 1.70 |
| | 1.80 |
| | - |
| | - |
/ | / | - |
| operator | 2018 |
Clippy Configuration
[package] edition = "2024" rust-version = "1.85" [lints.rust] unsafe_code = "warn" [lints.clippy] all = "warn" pedantic = "warn"
Common Clippy Lints
| Lint | Description |
|---|---|
| Enable all warnings |
| Stricter checks |
| Avoid unwrap |
| Prefer expect |
| Avoid cloning Arc |
Formatting (rustfmt)
# Use default config rustfmt src/lib.rs # Check formatting rustfmt --check src/lib.rs # Config file: .rustfmt.toml max_width = 100 tab_spaces = 4 edition = "2024"
Documentation Guidelines
/// Module documentation //! This module handles user authentication... /// Struct documentation /// /// # Examples /// ``` /// let user = User::new("name"); /// ``` pub struct User { ... } /// Method documentation /// /// # Arguments /// /// * `name` - User name /// /// # Returns /// /// Initialized user instance /// /// # Panics /// /// Panics when name is empty pub fn new(name: &str) -> Self { ... }
Workflow
Step 1: Name Things Properly
Choosing a name? → Function/variable? snake_case → Type/trait? CamelCase → Constant? SCREAMING_SNAKE_CASE → Conversion method? - Cheap view? as_foo() - Expensive? to_foo() - Consuming? into_foo()
Step 2: Format Code
# Run rustfmt cargo fmt # Check formatting in CI cargo fmt --check # Fix clippy warnings cargo clippy --fix
Step 3: Review Idioms
Check: → No unnecessary clone() → Use ? not unwrap() → &str in function parameters → Iterator methods not index loops → Meaningful error types
Quick Reference
Naming: snake_case (fn/var), CamelCase (type), SCREAMING_SNAKE_CASE (const) Format: rustfmt (just use it) Docs: /// for public items, //! for module docs Lint: #![warn(clippy::all)]
Review Checklist
When reviewing code:
- Naming follows Rust conventions
- Using
instead of?unwrap() - Avoiding unnecessary
clone() -
blocks have SAFETY commentsunsafe - Public APIs have doc comments
- Ran
cargo clippy - Ran
cargo fmt - No
prefix on accessor methodsget_ - Conversion methods named correctly (as/to/into)
- String parameters use
when possible&str
Verification Commands
# Format check cargo fmt --check # Lint check cargo clippy -- -D warnings # Documentation check cargo doc --no-deps --open # Run tests cargo test # Check naming conventions cargo clippy -- -W clippy::wrong_self_convention
Common Pitfalls
1. Wrong Method Naming
Symptom: Clippy warning
wrong_self_convention
// ❌ Bad: unnecessary get_ prefix impl User { fn get_name(&self) -> &str { &self.name } } // ✅ Good: direct accessor impl User { fn name(&self) -> &str { &self.name } }
2. String Type Misuse
Symptom: Unnecessary allocations
// ❌ Bad: forces allocation fn greet(name: String) { println!("Hello, {}", name); } // ✅ Good: accepts borrowed or owned fn greet(name: &str) { println!("Hello, {}", name); } // Both work now: greet("Alice"); // &str greet(&owned_string); // &String → &str
3. Index Loops
Symptom: Less idiomatic, error-prone
// ❌ Bad: manual indexing for i in 0..items.len() { println!("{}: {}", i, items[i]); } // ✅ Good: iterator for item in &items { println!("{}", item); } // ✅ Good: with index for (i, item) in items.iter().enumerate() { println!("{}: {}", i, item); }
Related Skills
- rust-anti-pattern - What not to do
- rust-error - Error handling patterns
- rust-performance - Performance idioms
- rust-async - Async conventions
- rust-unsafe - SAFETY comment style
Localized Reference
- Chinese version: SKILL_ZH.md - 完整中文版本,包含所有内容