Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Identifies and corrects common Rust anti-patterns like excessive clone, unwrap in production, and OOP-style Deref misuse.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
patterns/common-mistakes.md
1# Common Rust Anti-Patterns & Mistakes23## Ownership Anti-Patterns45### 1. Clone Everything67```rust8// ANTI-PATTERN: clone to avoid borrow checker9fn process(data: Vec<String>) {10for item in data.clone() { // unnecessary clone11println!("{}", item);12}13use_data(data);14}1516// BETTER: borrow when you don't need ownership17fn process(data: Vec<String>) {18for item in &data { // borrow instead19println!("{}", item);20}21use_data(data);22}23```2425### 2. Unnecessary Box2627```rust28// ANTI-PATTERN: boxing everything29fn get_value() -> Box<String> {30Box::new(String::from("hello"))31}3233// BETTER: return value directly34fn get_value() -> String {35String::from("hello")36}37```3839### 3. Holding References Too Long4041```rust42// ANTI-PATTERN: borrow prevents mutation43let mut data = vec![1, 2, 3];44let first = &data[0];45data.push(4); // ERROR: data is borrowed46println!("{}", first);4748// BETTER: scope the borrow49let mut data = vec![1, 2, 3];50let first = data[0]; // copy the value51data.push(4); // OK52println!("{}", first);53```5455---5657## Error Handling Anti-Patterns5859### 4. Unwrap Everywhere6061```rust62// ANTI-PATTERN: crashes on error63fn process_file(path: &str) {64let content = std::fs::read_to_string(path).unwrap();65let config: Config = toml::from_str(&content).unwrap();66}6768// BETTER: propagate errors69fn process_file(path: &str) -> Result<Config, Error> {70let content = std::fs::read_to_string(path)?;71let config: Config = toml::from_str(&content)?;72Ok(config)73}74```7576### 5. Ignoring Errors7778```rust79// ANTI-PATTERN: silent failure80let _ = file.write_all(data);8182// BETTER: handle or propagate83file.write_all(data)?;84// or at minimum, log the error85if let Err(e) = file.write_all(data) {86eprintln!("Warning: failed to write: {}", e);87}88```8990### 6. Panic in Library Code9192```rust93// ANTI-PATTERN: library panics94pub fn parse(input: &str) -> Data {95if input.is_empty() {96panic!("input cannot be empty");97}98// ...99}100101// BETTER: return Result102pub fn parse(input: &str) -> Result<Data, ParseError> {103if input.is_empty() {104return Err(ParseError::EmptyInput);105}106// ...107}108```109110---111112## String Anti-Patterns113114### 7. String Instead of &str115116```rust117// ANTI-PATTERN: forces allocation118fn greet(name: String) {119println!("Hello, {}", name);120}121122greet("world".to_string()); // allocation123124// BETTER: accept &str125fn greet(name: &str) {126println!("Hello, {}", name);127}128129greet("world"); // no allocation130```131132### 8. Format for Simple Concatenation133134```rust135// ANTI-PATTERN: format overhead136let greeting = format!("{}{}", "Hello, ", name);137138// BETTER for simple cases: push_str139let mut greeting = String::from("Hello, ");140greeting.push_str(name);141142// Or use + for String + &str143let greeting = String::from("Hello, ") + name;144```145146### 9. Repeated String Operations147148```rust149// ANTI-PATTERN: O(n²) allocations150let mut result = String::new();151for word in words {152result = result + word + " ";153}154155// BETTER: join156let result = words.join(" ");157158// Or with_capacity + push_str159let mut result = String::with_capacity(total_len);160for word in words {161result.push_str(word);162result.push(' ');163}164```165166---167168## Collection Anti-Patterns169170### 10. Index Instead of Iterator171172```rust173// ANTI-PATTERN: bounds checking overhead174for i in 0..vec.len() {175process(vec[i]);176}177178// BETTER: iterator179for item in &vec {180process(item);181}182```183184### 11. Collect Then Iterate185186```rust187// ANTI-PATTERN: unnecessary allocation188let filtered: Vec<_> = items.iter().filter(|x| x.valid).collect();189for item in filtered {190process(item);191}192193// BETTER: chain iterators194for item in items.iter().filter(|x| x.valid) {195process(item);196}197```198199### 12. Wrong Collection Type200201```rust202// ANTI-PATTERN: Vec for frequent membership checks203let allowed: Vec<&str> = vec!["a", "b", "c"];204if allowed.contains(&input) { ... } // O(n)205206// BETTER: HashSet for membership207use std::collections::HashSet;208let allowed: HashSet<&str> = ["a", "b", "c"].into();209if allowed.contains(input) { ... } // O(1)210```211212---213214## Concurrency Anti-Patterns215216### 13. Mutex for Read-Heavy Data217218```rust219// ANTI-PATTERN: Mutex when mostly reading220let data = Arc::new(Mutex::new(config));221// All readers block each other222223// BETTER: RwLock for read-heavy workloads224let data = Arc::new(RwLock::new(config));225// Multiple readers can proceed in parallel226```227228### 14. Holding Lock Across Await229230```rust231// ANTI-PATTERN: lock held across await232async fn bad() {233let guard = mutex.lock().unwrap();234some_async_op().await; // lock held!235use(guard);236}237238// BETTER: scope the lock239async fn good() {240let value = {241let guard = mutex.lock().unwrap();242guard.clone()243}; // lock released244some_async_op().await;245use(value);246}247```248249### 15. Blocking in Async250251```rust252// ANTI-PATTERN: blocking call in async253async fn bad() {254std::thread::sleep(Duration::from_secs(1)); // blocks executor!255}256257// BETTER: async sleep258async fn good() {259tokio::time::sleep(Duration::from_secs(1)).await;260}261262// For CPU work: spawn_blocking263async fn compute() {264tokio::task::spawn_blocking(|| heavy_work()).await265}266```267268---269270## Type System Anti-Patterns271272### 16. Stringly Typed273274```rust275// ANTI-PATTERN: strings for everything276fn connect(host: &str, port: &str, timeout: &str) { ... }277connect("8080", "localhost", "30"); // wrong order!278279// BETTER: strong types280struct Host(String);281struct Port(u16);282struct Timeout(Duration);283284fn connect(host: Host, port: Port, timeout: Timeout) { ... }285```286287### 17. Boolean Parameters288289```rust290// ANTI-PATTERN: what does true mean?291fn fetch(url: &str, use_cache: bool, validate_ssl: bool) { ... }292fetch("https://...", true, false); // unclear293294// BETTER: builder or named parameters295struct FetchOptions {296use_cache: bool,297validate_ssl: bool,298}299300fn fetch(url: &str, options: FetchOptions) { ... }301fetch("https://...", FetchOptions {302use_cache: true,303validate_ssl: false,304});305```306307### 18. Option<Option<T>>308309```rust310// ANTI-PATTERN: nested Option311fn find(id: u32) -> Option<Option<User>> { ... }312// What does None vs Some(None) mean?313314// BETTER: use Result or custom enum315enum FindResult {316Found(User),317NotFound,318Error(String),319}320```321322---323324## API Design Anti-Patterns325326### 19. Taking Ownership Unnecessarily327328```rust329// ANTI-PATTERN: takes ownership but doesn't need it330fn validate(config: Config) -> bool {331config.timeout > 0 && config.retries >= 0332}333334// BETTER: borrow335fn validate(config: &Config) -> bool {336config.timeout > 0 && config.retries >= 0337}338```339340### 20. Returning References to Temporaries341342```rust343// ANTI-PATTERN: impossible lifetime344fn get_default() -> &str {345let s = String::from("default");346&s // ERROR: s is dropped347}348349// BETTER: return owned350fn get_default() -> String {351String::from("default")352}353354// Or return static355fn get_default() -> &'static str {356"default"357}358```359360### 21. Overly Generic Functions361362```rust363// ANTI-PATTERN: complex generics for simple function364fn process<T, U, V>(input: T) -> V365where366T: Into<U>,367U: AsRef<str> + Clone,368V: From<String>,369{ ... }370371// BETTER: concrete types if generics not needed372fn process(input: &str) -> String { ... }373```374375---376377## Macro Anti-Patterns378379### 22. Macro When Function Works380381```rust382// ANTI-PATTERN: macro for simple operation383macro_rules! add {384($a:expr, $b:expr) => { $a + $b };385}386387// BETTER: just use a function388fn add(a: i32, b: i32) -> i32 { a + b }389```390391### 23. Complex Macro Without Tests392393```rust394// ANTI-PATTERN: complex macro with no tests395macro_rules! define_api {396// ... 100 lines of macro code ...397}398399// BETTER: test macro outputs400#[test]401fn test_macro_expansion() {402// Use cargo-expand or trybuild403}404```405406---407408## Quick Reference409410| Anti-Pattern | Better Alternative |411|--------------|-------------------|412| Clone everywhere | Borrow when possible |413| Unwrap everywhere | Propagate with `?` |414| `String` parameters | `&str` parameters |415| Index loops | Iterator loops |416| Collect then process | Chain iterators |417| Mutex for reads | RwLock for read-heavy |418| Lock across await | Scope the lock |419| Blocking in async | spawn_blocking |420| Stringly typed | Strong types |421| Boolean params | Builders or enums |422