rust-development
Use when writing Rust code for memory safety, performance, and systems programming
安装与使用
请根据来源仓库和你的 AI 工具说明安装此技能。先阅读技能文件和依赖要求,再添加到工作流。
查看来源 ↗使用指南技能说明
Rust Development
Guidelines for safe, performant, and idiomatic Rust code.
When to Use
- Borrow checker errors ("cannot borrow as mutable")
- Lifetime annotation issues
- Trait bound compilation errors
- Memory safety requirements
- Systems programming tasks
- High-performance concurrent code
When NOT to Use
- Prototyping with frequent schema changes (use Python)
- Simple scripts (use Bash/Python)
- When compilation time is critical
Core Principles
- Memory Safety - Leverage ownership system for zero-cost safety
- Performance - Zero-cost abstractions and efficient code
- Fearless Concurrency - Safe parallel programming
- Explicit Error Handling - Use Result<T, E> and Option<T>
- Idiomatic Patterns - Follow Rust conventions
Ownership and Borrowing
Basic Rules
// Each value has a single owner
let s1 = String::from("hello");
let s2 = s1; // s1 moved, no longer valid
// Borrow without taking ownership
fn length(s: &String) -> usize { s.len() }
// Mutable references are exclusive
let mut s = String::from("hello");
let r1 = &mut s;
// let r2 = &mut s; // ❌ Cannot have two mutable refs
Common Patterns
// Multiple immutable borrows OK
let s = String::from("hello");
let r1 = &s;
let r2 = &s; // ✅
// Scoping mutable borrow
let mut s = String::from("hello");
{
let r1 = &mut s;
r1.push_str(", world");
} // r1 goes out of scope
println!("{}", s); // ✅
Error Handling
Result<T, E>
use std::fs::File;
use std::io::Read;
// ❌ Don't unwrap() in production
fn read_file_bad(path: &str) -> String {
let mut file = File::open(path).unwrap(); // Panics on error
let mut contents = String::new();
file.read_to_string(&mut contents).unwrap();
contents
}
// ✅ Proper error handling with ? operator
fn read_file(path: &str) -> Result<String, std::io::Error> {
let mut file = File::open(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
// ✅ Custom error types
#[derive(Debug)]
enum ConfigError {
Io(std::io::Error),
Parse(String),
}
impl From<std::io::Error> for ConfigError {
fn from(err: std::io::Error) -> Self {
ConfigError::Io(err)
}
}
Option<T>
fn find_user(id: u32) -> Option<User> { /* ... */ }
// Pattern matching
match find_user(123) {
Some(user) => println!("Found: {}", user.name),
None => println!("User not found"),
}
// Combinators
let name = find_user(123)
.map(|user| user.name)
.unwrap_or_else(|| "Unknown".to_string());
Memory Management
Smart Pointers
use std::rc::Rc;
use std::sync::Arc;
use std::cell::RefCell;
// Reference counting (single-threaded)
let data = Rc::new(vec![1, 2, 3]);
let data_clone = Rc::clone(&data);
// Thread-safe reference counting
let shared = Arc::new(vec![1, 2, 3]);
let thread_data = Arc::clone(&shared);
// Interior mutability
let data = RefCell::new(vec![1, 2, 3]);
data.borrow_mut().push(4);
Lifetimes
// Explicit lifetime annotations
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
// Struct with lifetime
struct Excerpt<'a> {
part: &'a str,
}
impl<'a> Excerpt<'a> {
fn level(&self) -> i32 { 3 }
}
Concurrency
Thread Safety with Arc<Mutex<T>>
use std::sync::{Arc, Mutex};
use std::thread;
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
*counter.lock().unwrap() += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
Async/Await (Tokio)
use tokio;
async fn fetch_data(url: &str) -> Result<String, reqwest::Error> {
let body = reqwest::get(url).await?.text().await?;
Ok(body)
}
// Concurrent async operations
async fn fetch_multiple() -> Result<Vec<String>, Box<dyn std::error::Error>> {
let urls = vec!["https://api1.com", "https://api2.com"];
let futures: Vec<_> = urls.iter().map(|&url| fetch_data(url)).collect();
let results = futures::future::try_join_all(futures).await?;
Ok(results)
}
Performance
Zero-Cost Abstractions
// Iterator chains compile to efficient loops
let sum: i32 = (0..1_000_000)
.filter(|x| x % 2 == 0)
.map(|x| x * x)
.sum();
// Use slices over Vec when possible
fn analyze(data: &[f64]) -> f64 {
data.iter().sum::<f64>() / data.len() as f64
}
Memory Efficiency
// Box large stack allocations
enum Message {
Quit,
Move { x: i32, y: i32 },
ChangeColor(Box<[u8; 1024]>), // Box large arrays
}
Testing
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_calculation() {
assert_eq!(calculate(2, 2), 4);
}
#[test]
#[should_panic(expected = "divide by zero")]
fn test_divide_by_zero() {
divide(10, 0);
}
#[test]
fn test_result() -> Result<(), Box<dyn std::error::Error>> {
let result = risky_operation()?;
assert_eq!(result, "success");
Ok(())
}
}
// Property-based testing
use quickcheck::quickcheck;
#[quickcheck]
fn prop_reverse_involutive(xs: Vec<u32>) -> bool {
let reversed: Vec<_> = xs.iter().rev().rev().cloned().collect();
xs == reversed
}
Best Practices Checklist
- Use
cargo clippyfor linting - Run
cargo fmtfor formatting - Handle all Result/Option cases explicitly
- Prefer borrowing over taking ownership
- Use iterators over manual loops
- Implement proper Error types for libraries
- Add comprehensive documentation with
/// - Use
#[deny(missing_docs)]for public APIs - Profile with
cargo flamegraphfor performance - Test with
cargo testand property-based tests
Common Patterns
Builder Pattern
pub struct Config {
host: String,
port: u16,
timeout: Duration,
}
pub struct ConfigBuilder {
host: Option<String>,
port: Option<u16>,
timeout: Option<Duration>,
}
impl ConfigBuilder {
pub fn new() -> Self {
Self { host: None, port: None, timeout: None }
}
pub fn host(mut self, host: impl Into<String>) -> Self {
self.host = Some(host.into());
self
}
pub fn build(self) -> Result<Config, String> {
Ok(Config {
host: self.host.ok_or("host required")?,
port: self.port.unwrap_or(8080),
timeout: self.timeout.unwrap_or(Duration::from_secs(30)),
})
}
}
Type-State Pattern
pub struct Pending;
pub struct Running;
pub struct Task<State = Pending> {
id: u32,
_state: PhantomData<State>,
}
impl Task<Pending> {
pub fn new(id: u32) -> Self {
Task { id, _state: PhantomData }
}
pub fn start(self) -> Task<Running> {
Task { id: self.id, _state: PhantomData }
}
}
Anti-Patterns
// ❌ Over-using Clone
fn bad(data: Vec<String>) -> Vec<String> {
data.clone() // Unnecessary allocation
}
// ✅ Work with borrowing
fn good(data: &[String]) -> Vec<&str> {
data.iter().map(|s| s.as_str()).collect()
}
// ❌ Panic-prone unwrap()
let value = risky().unwrap();
// ✅ Handle errors properly
let value = risky().unwrap_or_else(|e| {
eprintln!("Failed: {}", e);
default_value()
});
Quick Reference
| Tool | Command | Purpose |
|---|---|---|
| Check | cargo check |
Fast syntax/type check |
| Lint | cargo clippy |
Catch common mistakes |
| Format | cargo fmt |
Format code |
| Test | cargo test |
Run tests |
| Docs | cargo doc --open |
Generate docs |
| Profile | cargo flamegraph |
Performance analysis |
Common Compiler Errors
| Error | Cause | Fix |
|---|---|---|
| "cannot borrow as mutable" | Multiple mutable refs | Use scopes or refactor |
| "does not live long enough" | Lifetime too short | Add lifetime annotation |
| "trait bounds not satisfied" | Missing trait impl | Derive or implement trait |
| "move occurs because..." | Value moved | Use reference or clone |
Remember
The compiler is your friend. When fighting the borrow checker, step back and consider if your design could be improved rather than working around the constraints.
使用示例
查看来源仓库中的使用示例与配置说明。
查看来源 ↗来源历史
- 收录时间
- 2026-01-20
- 索引更新时间
- 2026-01-26
- Branch
- main
收录与同步日期属于本站记录。源码修改历史请查看来源仓库。
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!