Main Site ↗

rust-language

by benchflow-ai890173GitHub

Guide for writing Rust code covering ownership, borrowing, lifetimes, error handling, async programming, and Rust best practices

Unlock Deep Analysis

Use AI to visualize the workflow and generate a realistic output preview for this skill.

Powered by Fastest LLM

Development
Compatible Agents
Claude Code
Claude Code
~/.claude/skills/
Codex CLI
Codex CLI
~/.codex/skills/
Gemini CLI
Gemini CLI
~/.gemini/skills/
O
OpenCode
~/.opencode/skills/
O
OpenClaw
~/.openclaw/skills/
GitHub Copilot
GitHub Copilot
~/.copilot/skills/
Cursor
Cursor
~/.cursor/skills/
W
Windsurf
~/.codeium/windsurf/skills/
C
Cline
~/.cline/skills/
R
Roo Code
~/.roo/skills/
K
Kiro
~/.kiro/skills/
J
Junie
~/.junie/skills/
A
Augment Code
~/.augment/skills/
W
Warp
~/.warp/skills/
G
Goose
~/.config/goose/skills/
SKILL.md

Rust Programming Language

This skill activates when writing Rust code, understanding ownership and borrowing, working with async Rust, or following Rust best practices.

When to Use This Skill

Activate when:

  • Writing Rust code
  • Understanding ownership, borrowing, and lifetimes
  • Implementing error handling with Result and Option
  • Working with traits and generics
  • Writing async/concurrent Rust code
  • Using Cargo and managing dependencies
  • Following Rust idioms and best practices

Ownership and Borrowing

Ownership Rules

Rust's core concept - every value has exactly one owner:

// Ownership transfer (move)
let s1 = String::from("hello");
let s2 = s1;  // s1 is no longer valid
// println!("{}", s1);  // Error!
println!("{}", s2);  // OK

// Copy types (stack-only data)
let x = 5;
let y = x;  // x is still valid (Copy trait)
println!("{} {}", x, y);  // OK

Borrowing

// Immutable borrow
fn calculate_length(s: &String) -> usize {
    s.len()
}

let s = String::from("hello");
let len = calculate_length(&s);
println!("{} has length {}", s, len);  // s still valid

// Mutable borrow
fn append_world(s: &mut String) {
    s.push_str(" world");
}

let mut s = String::from("hello");
append_world(&mut s);
println!("{}", s);  // "hello world"

Borrowing Rules

// Rule 1: Multiple immutable borrows OK
let s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{} {}", r1, r2);  // OK

// Rule 2: Only ONE mutable borrow at a time
let mut s = String::from("hello");
let r1 = &mut s;
// let r2 = &mut s;  // Error!
println!("{}", r1);

// Rule 3: Cannot have mutable and immutable borrows together
let mut s = String::from("hello");
let r1 = &s;
// let r2 = &mut s;  // Error!
println!("{}", r1);

Slices

// String slices
let s = String::from("hello world");
let hello = &s[0..5];
let world = &s[6..11];

// Array slices
let arr = [1, 2, 3, 4, 5];
let slice = &arr[1..3];  // [2, 3]

// Function taking slice
fn first_word(s: &str) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}

Lifetimes

Lifetime Annotations

// Explicit lifetime annotation
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

// Usage
let s1 = String::from("long string");
let s2 = String::from("short");
let result = longest(&s1, &s2);
println!("Longest: {}", result);

Lifetime in Structs

// Struct with lifetime
struct ImportantExcerpt<'a> {
    part: &'a str,
}

impl<'a> ImportantExcerpt<'a> {
    fn announce_and_return(&self) -> &str {
        println!("Attention: {}", self.part);
        self.part
    }
}

// Usage
let novel = String::from("Call me Ishmael. Some years ago...");
let first_sentence = novel.split('.').next().unwrap();
let excerpt = ImportantExcerpt { part: first_sentence };

Lifetime Elision

// Compiler infers lifetimes (no annotation needed)
fn first_word(s: &str) -> &str {
    // Compiler infers: fn first_word<'a>(s: &'a str) -> &'a str
    let bytes = s.as_bytes();
    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }
    &s[..]
}

Error Handling

Result Type

use std::fs::File;
use std::io::{self, Read};

// Returning Result
fn read_username_from_file() -> Result<String, io::Error> {
    let mut file = File::open("username.txt")?;
    let mut username = String::new();
    file.read_to_string(&mut username)?;
    Ok(username)
}

// Using Result
match read_username_from_file() {
    Ok(username) => println!("Username: {}", username),
    Err(e) => println!("Error: {}", e),
}

Option Type

// Option for optional values
fn find_user(id: u32) -> Option<User> {
    if id == 1 {
        Some(User { id: 1, name: "Alice".to_string() })
    } else {
        None
    }
}

// Using Option
match find_user(1) {
    Some(user) => println!("Found: {}", user.name),
    None => println!("User not found"),
}

// Option combinators
let user = find_user(1)
    .map(|u| u.name)
    .unwrap_or("Unknown".to_string());

The ? Operator

// ? operator for error propagation
fn read_file(path: &str) -> Result<String, io::Error> {
    let mut file = File::open(path)?;  // Returns early if Err
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
}

// Chaining with ?
fn process_file(path: &str) -> Result<usize, io::Error> {
    let contents = read_file(path)?;
    Ok(contents.len())
}

Custom Error Types

use std::fmt;

#[derive(Debug)]
enum AppError {
    Io(io::Error),
    Parse(std::num::ParseIntError),
    Custom(String),
}

impl fmt::Display for AppError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            AppError::Io(e) => write!(f, "IO error: {}", e),
            AppError::Parse(e) => write!(f, "Parse error: {}", e),
            AppError::Custom(s) => write!(f, "Error: {}", s),
        }
    }
}

impl From<io::Error> for AppError {
    fn from(error: io::Error) -> Self {
        AppError::Io(error)
    }
}

// Usage
fn process() -> Result<(), AppError> {
    let file = File::open("data.txt")?;  // Auto-converts io::Error
    // ...
    Ok(())
}

Traits

Defining Traits

// Define a trait
trait Summary {
    fn summarize(&self) -> String;

    // Default implementation
    fn summarize_author(&self) -> String {
        String::from("(Read more...)")
    }
}

// Implement trait
struct Article {
    title: String,
    content: String,
}

impl Summary for Article {
    fn summarize(&self) -> String {
        format!("{}: {}", self.title, self.content)
    }
}

Trait Bounds

// Function with trait bound
fn notify<T: Summary>(item: &T) {
    println!("Breaking news! {}", item.summarize());
}

// Multiple trait bounds
fn process<T: Summary + Display>(item: &T) {
    // ...
}

// Where clause (clearer for complex bounds)
fn complex<T, U>(t: &T, u: &U)
where
    T: Summary + Clone,
    U: Summary + Debug,
{
    // ...
}

// impl Trait syntax
fn returns_summarizable() -> impl Summary {
    Article {
        title: String::from("Title"),
        content: String::from("Content"),
    }
}

Common Traits

// Clone and Copy
#[derive(Clone)]
struct Point {
    x: i32,
    y: i32,
}

// Debug
#[derive(Debug)]
struct User {
    name: String,
    age: u32,
}

// PartialEq and Eq
#[derive(PartialEq, Eq)]
struct Id(u32);

// PartialOrd and Ord
#[derive(PartialOrd, Ord, PartialEq, Eq)]
struct Priority(u32);

Generics

Generic Functions

// Generic function
fn largest<T: PartialOrd>(list: &[T]) -> &T {
    let mut largest = &list[0];

    for item in list {
        if item > largest {
            largest = item;
        }
    }

    largest
}

// Usage
let numbers = vec![34, 50, 25, 100, 65];
let result = largest(&numbers);

let chars = vec!['y', 'm', 'a', 'q'];
let result = largest(&chars);

Generic Structs

// Generic struct
struct Point<T> {
    x: T,
    y: T,
}

impl<T> Point<T> {
    fn new(x: T, y: T) -> Self {
        Point { x, y }
    }
}

// Specific implementation for certain types
impl Point<f64> {
    fn distance_from_origin(&self) -> f64 {
        (self.x.powi(2) + self.y.powi(2)).sqrt()
    }
}

// Multiple type parameters
struct Pair<T, U> {
    first: T,
    second: U,
}

Generic Enums

// Option is a generic enum
enum Option<T> {
    Some(T),
    None,
}

// Result is a generic enum
enum Result<T, E> {
    Ok(T),
    Err(E),
}

Collections

Vectors

// Create vector
let mut v: Vec<i32> = Vec::new();
let v = vec![1, 2, 3];

// Add elements
v.push(4);
v.push(5);

// Access elements
let third = &v[2];  // Panics if out of bounds
let third = v.get(2);  // Returns Option<&T>

// Iterate
for i in &v {
    println!("{}", i);
}

// Iterate and modify
for i in &mut v {
    *i += 50;
}

HashMaps

use std::collections::HashMap;

// Create HashMap
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);

// Access values
let team = String::from("Blue");
let score = scores.get(&team);  // Returns Option<&V>

// Iterate
for (key, value) in &scores {
    println!("{}: {}", key, value);
}

// Update values
scores.entry(String::from("Blue")).or_insert(0);
*scores.entry(String::from("Blue")).or_insert(0) += 10;

Strings

// Create strings
let s = String::from("hello");
let s = "hello".to_string();

// Concatenation
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2;  // s1 is moved

// format! macro
let s = format!("{}-{}", "hello", "world");

// Iterate
for c in "hello".chars() {
    println!("{}", c);
}

// Slicing (be careful with UTF-8!)
let hello = "Здравствуйте";
let s = &hello[0..4];  // "Зд"

Pattern Matching

Match Expressions

// Basic match
let number = 7;
match number {
    1 => println!("One"),
    2 | 3 | 5 | 7 | 11 => println!("Prime"),
    13..=19 => println!("Teen"),
    _ => println!("Other"),
}

// Match with destructuring
struct Point {
    x: i32,
    y: i32,
}

let p = Point { x: 0, y: 7 };
match p {
    Point { x: 0, y } => println!("On y axis at {}", y),
    Point { x, y: 0 } => println!("On x axis at {}", x),
    Point { x, y } => println!("At ({}, {})", x, y),
}

If Let

// if let for simple matches
let some_value = Some(3);

if let Some(3) = some_value {
    println!("three");
}

// With else
if let Some(x) = some_value {
    println!("{}", x);
} else {
    println!("None");
}

While Let

// while let for loops
let mut stack = vec![1, 2, 3];

while let Some(top) = stack.pop() {
    println!("{}", top);
}

Async Programming

Async Functions

use tokio;

// Async function
async fn fetch_data(url: &str) -> Result<String, reqwest::Error> {
    let response = reqwest::get(url).await?;
    let body = response.text().await?;
    Ok(body)
}

// Using async function
#[tokio::main]
async fn main() {
    match fetch_data("https://example.com").await {
        Ok(data) => println!("Data: {}", data),
        Err(e) => println!("Error: {}", e),
    }
}

Concurrent Async Operations

use tokio;

async fn fetch_multiple() {
    // Sequential
    let data1 = fetch_data("https://api1.com").await;
    let data2 = fetch_data("https://api2.com").await;

    // Concurrent with join!
    let (data1, data2) = tokio::join!(
        fetch_data("https://api1.com"),
        fetch_data("https://api2.com")
    );

    // Concurrent with spawn
    let handle1 = tokio::spawn(fetch_data("https://api1.com"));
    let handle2 = tokio::spawn(fetch_data("https://api2.com"));

    let data1 = handle1.await.unwrap();
    let data2 = handle2.await.unwrap();
}

Streams

use tokio_stream::StreamExt;

async fn process_stream() {
    let mut stream = tokio_stream::iter(vec![1, 2, 3, 4, 5]);

    while let Some(value) = stream.next().await {
        println!("Value: {}", value);
    }
}

Concurrency

Threads

use std::thread;
use std::time::Duration;

// Spawn thread
let handle = thread::spawn(|| {
    for i in 1..10 {
        println!("Thread: {}", i);
        thread::sleep(Duration::from_millis(1));
    }
});

handle.join().unwrap();

// Move data into thread
let v = vec![1, 2, 3];
let handle = thread::spawn(move || {
    println!("Vector: {:?}", v);
});

Channels

use std::sync::mpsc;

// Create channel
let (tx, rx) = mpsc::channel();

// Send from thread
thread::spawn(move || {
    tx.send("hello").unwrap();
});

// Receive
let received = rx.recv().unwrap();
println!("Received: {}", received);

// Multiple senders
let (tx, rx) = mpsc::channel();
let tx1 = tx.clone();

thread::spawn(move || tx.send("from thread 1").unwrap());
thread::spawn(move || tx1.send("from thread 2").unwrap());

for received in rx {
    println!("{}", received);
}

Shared State

use std::sync::{Arc, Mutex};

// Arc for shared ownership, Mutex for mutual exclusion
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 || {
        let mut num = counter.lock().unwrap();
        *num += 1;
    });
    handles.push(handle);
}

for handle in handles {
    handle.join().unwrap();
}

println!("Result: {}", *counter.lock().unwrap());

Testing

Unit Tests

// Tests in same file
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }

    #[test]
    fn test_add() {
        assert_eq!(add(2, 2), 4);
    }

    #[test]
    #[should_panic]
    fn test_panic() {
        panic!("This should panic");
    }

    #[test]
    fn test_result() -> Result<(), String> {
        if 2 + 2 == 4 {
            Ok(())
        } else {
            Err(String::from("two plus two does not equal four"))
        }
    }
}

fn add(a: i32, b: i32) -> i32 {
    a + b
}

Integration Tests

// tests/integration_test.rs
use my_crate;

#[test]
fn test_integration() {
    assert_eq!(my_crate::add(2, 2), 4);
}

Running Tests

# Run all tests
cargo test

# Run specific test
cargo test test_add

# Run with output
cargo test -- --nocapture

# Run integration tests only
cargo test --test integration_test

Cargo and Dependencies

Cargo.toml

[package]
name = "my_project"
version = "0.1.0"
edition = "2021"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
reqwest = "0.11"

[dev-dependencies]
mockall = "0.11"

[profile.release]
opt-level = 3
lto = true

Common Commands

# Create new project
cargo new my_project
cargo new --lib my_lib

# Build
cargo build
cargo build --release

# Run
cargo run
cargo run --release

# Test
cargo test

# Check (faster than build)
cargo check

# Format code
cargo fmt

# Lint
cargo clippy

# Update dependencies
cargo update

# Add dependency
cargo add serde

Best Practices

Prefer Borrowing

// Good: Borrow when possible
fn process(data: &Vec<i32>) {
    // Use data without taking ownership
}

// Avoid: Taking ownership unless needed
fn process(data: Vec<i32>) {
    // Can't use data after calling this
}

Use ? for Error Propagation

// Good: Use ? operator
fn read_file(path: &str) -> Result<String, io::Error> {
    let mut file = File::open(path)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
}

// Avoid: Manual match for each error
fn read_file(path: &str) -> Result<String, io::Error> {
    let mut file = match File::open(path) {
        Ok(f) => f,
        Err(e) => return Err(e),
    };
    // ...
}

Use Iterators

// Good: Iterators (lazy, efficient)
let sum: i32 = vec![1, 2, 3, 4, 5]
    .iter()
    .filter(|x| *x % 2 == 0)
    .map(|x| x * 2)
    .sum();

// Avoid: Manual loops when iterators work
let mut sum = 0;
for x in vec![1, 2, 3, 4, 5] {
    if x % 2 == 0 {
        sum += x * 2;
    }
}

Prefer &str over &String

// Good: Accept string slices
fn greet(name: &str) {
    println!("Hello, {}", name);
}

// Can be called with both &str and &String
greet("Alice");
greet(&String::from("Bob"));

// Less flexible: Only accepts &String
fn greet(name: &String) {
    println!("Hello, {}", name);
}

Common Patterns

Builder Pattern

#[derive(Default)]
struct User {
    name: String,
    email: String,
    age: Option<u32>,
}

impl User {
    fn builder() -> UserBuilder {
        UserBuilder::default()
    }
}

#[derive(Default)]
struct UserBuilder {
    name: String,
    email: String,
    age: Option<u32>,
}

impl UserBuilder {
    fn name(mut self, name: impl Into<String>) -> Self {
        self.name = name.into();
        self
    }

    fn email(mut self, email: impl Into<String>) -> Self {
        self.email = email.into();
        self
    }

    fn age(mut self, age: u32) -> Self {
        self.age = Some(age);
        self
    }

    fn build(self) -> User {
        User {
            name: self.name,
            email: self.email,
            age: self.age,
        }
    }
}

// Usage
let user = User::builder()
    .name("Alice")
    .email("alice@example.com")
    .age(30)
    .build();

Newtype Pattern

// Newtype for type safety
struct Meters(f64);
struct Seconds(f64);

fn calculate_speed(distance: Meters, time: Seconds) -> f64 {
    distance.0 / time.0
}

// Can't accidentally swap parameters
let speed = calculate_speed(Meters(100.0), Seconds(9.8));

Key Principles

  • Ownership ensures memory safety: No garbage collector needed
  • Borrow checker prevents data races: Compile-time safety
  • Zero-cost abstractions: High-level code compiles to efficient machine code
  • Explicit over implicit: Be clear about ownership, mutability, errors
  • Prefer immutability: Use mut only when needed
  • Use the type system: Let the compiler catch errors
  • Test thoroughly: Tests are first-class in Rust
  • Use clippy: Catch common mistakes and non-idiomatic code

Source: https://github.com/benchflow-ai/SkillsBench#registry-terminal_bench_2.0-full_batch_reviewed-terminal_bench_2_0_polyglot-rust-c-environment-skills-rust-language

Content curated from original sources, copyright belongs to authors

Grade B
-AI Score
Best Practices
Checking...
Try this Skill

User Rating

USER RATING

0UP
0DOWN
Loading files...

WORKS WITH

Claude Code
Claude
Codex CLI
Codex
Gemini CLI
Gemini
O
OpenCode
O
OpenClaw
GitHub Copilot
Copilot
Cursor
Cursor
W
Windsurf
C
Cline
R
Roo
K
Kiro
J
Junie
A
Augment
W
Warp
G
Goose