スキル一覧に戻る
gar-ai

rust-memory

by gar-ai

1🍴 0📅 2025年12月31日
GitHubで見るManusで実行

SKILL.md


name: rust-memory description: Minimize allocations and cloning using references, Cow, and smart pointers. Use when optimizing hot paths or memory-constrained code.

Memory Efficiency

Patterns to minimize allocations and copies in Rust.

Avoid Unnecessary Cloning

// BAD: Cloning when not needed
fn process(data: Vec<String>) -> Vec<String> {
    data.clone().iter().map(|s| s.to_uppercase()).collect()
}

// GOOD: Take ownership or borrow
fn process(data: Vec<String>) -> Vec<String> {
    data.into_iter().map(|s| s.to_uppercase()).collect()
}

// GOOD: Return iterator for lazy evaluation
fn process(data: &[String]) -> impl Iterator<Item = String> + '_ {
    data.iter().map(|s| s.to_uppercase())
}

Prefer &str over String

// BAD: Requires allocation
fn greet(name: String) {
    println!("Hello, {}!", name);
}

// GOOD: Accepts any string-like type
fn greet(name: &str) {
    println!("Hello, {}!", name);
}

// BEST: Generic for flexibility
fn greet(name: impl AsRef<str>) {
    println!("Hello, {}!", name.as_ref());
}

Pre-allocate Collections

// BAD: Multiple reallocations as vector grows
let mut v = Vec::new();
for i in 0..1000 {
    v.push(i);
}

// GOOD: Single allocation
let mut v = Vec::with_capacity(1000);
for i in 0..1000 {
    v.push(i);
}

// Also works for String and HashMap
let mut s = String::with_capacity(4000);
let mut map = HashMap::with_capacity(100);

Copy-on-Write (Cow)

use std::borrow::Cow;

// Return borrowed if no modification needed, owned if modified
fn normalize_path(path: &str) -> Cow<'_, str> {
    if path.contains("//") {
        Cow::Owned(path.replace("//", "/"))
    } else {
        Cow::Borrowed(path)
    }
}

// Usage - no allocation if already normalized
let normalized = normalize_path("/home/user");  // Borrowed
let fixed = normalize_path("/home//user");      // Owned

// Cow in structs
struct Config<'a> {
    name: Cow<'a, str>,
}

impl<'a> Config<'a> {
    fn new(name: &'a str) -> Self {
        Self { name: Cow::Borrowed(name) }
    }

    fn with_prefix(mut self, prefix: &str) -> Self {
        self.name = Cow::Owned(format!("{}{}", prefix, self.name));
        self
    }
}

Smart Pointers

use std::sync::Arc;
use std::rc::Rc;

// Arc - Shared ownership across threads (atomic reference counting)
let data = Arc::new(expensive_data);
let data_clone = Arc::clone(&data);  // Cheap clone, shares data

// Rc - Single-threaded shared ownership
let data = Rc::new(expensive_data);
let data_clone = Rc::clone(&data);

// Box - Heap allocation for large data or recursive types
let large_data = Box::new([0u8; 1_000_000]);

// Arc::clone is explicit about what it does
// Prefer Arc::clone(&x) over x.clone() for clarity

Zero-Copy with Bytes

use bytes::Bytes;

// Bytes: Reference-counted, immutable bytes
let data = Bytes::from(vec![0u8; 1024]);
let slice = data.slice(0..512);  // No copy, shares underlying buffer

// BytesMut for building buffers
use bytes::BytesMut;

let mut buf = BytesMut::with_capacity(1024);
buf.extend_from_slice(b"hello");
buf.extend_from_slice(b" world");
let frozen = buf.freeze();  // Convert to immutable Bytes

SmallVec for Small Collections

use smallvec::SmallVec;

// Stack-allocated if <= 8 items, heap otherwise
let mut results: SmallVec<[Result; 8]> = SmallVec::new();
results.push(Ok(1));
results.push(Ok(2));
// No heap allocation for common case

Avoid Intermediate Collections

// BAD: Creates intermediate Vec
let sum: i32 = data
    .iter()
    .filter(|&&x| x > 2)
    .collect::<Vec<_>>()  // Unnecessary allocation
    .iter()
    .map(|&&x| x * 2)
    .sum();

// GOOD: Chain iterators, single pass
let sum: i32 = data
    .iter()
    .filter(|&&x| x > 2)
    .map(|&x| x * 2)
    .sum();

String Building

// BAD: Multiple allocations
let s = String::new() + "hello" + " " + "world";

// GOOD: Pre-allocate and push
let mut s = String::with_capacity(11);
s.push_str("hello");
s.push(' ');
s.push_str("world");

// GOOD: Use format! for clarity (single allocation)
let s = format!("hello {} world", name);

// BEST for loops: Join
let parts = vec!["hello", "world"];
let s = parts.join(" ");

Take and Replace

// Extract value without cloning
struct Container {
    data: Option<Vec<u8>>,
}

impl Container {
    fn take_data(&mut self) -> Option<Vec<u8>> {
        self.data.take()  // Replaces with None, returns original
    }
}

// Replace and get old value
let mut value = 5;
let old = std::mem::replace(&mut value, 10);
assert_eq!(old, 5);
assert_eq!(value, 10);

Guidelines

  • Use &str instead of String for parameters
  • Pre-allocate with with_capacity() when size is known
  • Use Cow for "maybe modified" returns
  • Prefer Arc::clone(&x) over x.clone() for clarity
  • Use Bytes for zero-copy buffer sharing
  • Chain iterators instead of collecting intermediates
  • Use take() and replace() to avoid cloning

Examples

See hercules-local-algo/src/pipeline/ for memory-efficient patterns.

スコア

総合スコア

60/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です