Use Cases (अपडेट: 2/6/2026)

Claude Code के साथ Rust विकास: Cargo, ownership, tests और CLI refactor

Claude Code से Rust सीखने की गाइड: Cargo, ownership, tests, fmt, clippy, errors और छोटा CLI उदाहरण।

Claude Code के साथ Rust विकास: Cargo, ownership, tests और CLI refactor

Rust को छोटे और जांचे जा सकने वाले काम से शुरू करें

Rust शुरू में कठिन लग सकता है, क्योंकि इसमें ownership, borrowing, lifetime और Result आधारित error handling जैसे विचार आते हैं। आसान भाषा में, ownership का मतलब है “डेटा किसके पास है”, borrowing का मतलब है “डेटा को थोड़ी देर पढ़ना या बदलना, लेकिन उसका मालिक न बनना”, और lifetime बताता है कि reference कितनी देर तक valid है। Claude Code इस सीखने की प्रक्रिया में उपयोगी है, लेकिन इसे बिना जांचे code generator की तरह नहीं चलाना चाहिए। इसे compiler errors पढ़ाने, छोटे file edit कराने और test commands चलाने के लिए इस्तेमाल करें।

इस लेख में हम tasknote नाम का छोटा CLI बनाएंगे। यह tasks.txt में [ ] task और [x] task पढ़ता है, फिर summary या केवल open tasks दिखाता है। आधिकारिक संदर्भ के लिए Rust Book ownership, Cargo Book project setup, cargo test, rustfmt, Clippy और Claude Code overview देखें।

अगर Claude Code नया है, तो पहले getting started guide पढ़ें। team workflow के लिए नियम CLAUDE.md best practices में लिखें और risky commands को permissions guide से सीमित करें।

flowchart LR
  Prompt["लक्ष्य और सीमा"]
  Cargo["छोटा Cargo project"]
  Compiler["ownership error पढ़ना"]
  Tests["tests से behavior fix"]
  Quality["fmt और clippy"]
  Refactor["छोटा refactor"]

  Prompt --> Cargo --> Compiler --> Tests --> Quality --> Refactor

Cargo project बनाना

Cargo Rust का standard tool है। यह project बनाता है, build करता है, run करता है, tests चलाता है और dependencies संभालता है। Claude Code से code लिखवाने से पहले verification commands तय कर दें।

cargo new tasknote --bin
cd tasknote
cargo run

इससे Cargo.toml और src/main.rs बनते हैं। नए projects में edition = "2024" दिख सकता है, इसलिए Claude Code से actual manifest पढ़वाएं। इस उदाहरण में केवल clap और anyhow चाहिए।

[package]
name = "tasknote"
version = "0.1.0"
edition = "2024"

[dependencies]
anyhow = "1"
clap = { version = "4", features = ["derive"] }

पहला prompt implementation नहीं, design मांगना चाहिए।

इस Cargo project में `tasknote` CLI बनाना है।
यह `tasks.txt` से `[ ] task` और `[x] task` lines पढ़ेगा।
पहले केवल `Cargo.toml`, `src/lib.rs`, `src/main.rs` का design बताएं।
अभी files edit न करें। ownership और error handling का कारण भी समझाएं।

Rust में शुरुआत की design choice बाद के code को आसान या कठिन बना देती है। इसलिए “कौन data own करेगा” और “कौन सिर्फ borrow करेगा” पहले साफ करें।

Ownership और borrowing पर सही सवाल

इस CLI में file content पहले String में आता है। parse_tasks इसे &str के रूप में पढ़ता है, क्योंकि उसे ownership नहीं चाहिए। parsed result Vec<Task> है, जिसमें हर task अपना title own करता है। summarize केवल पढ़ता है, इसलिए वह &[Task] लेता है।

`parse_tasks(input: &str) -> Vec<Task>` और `summarize(tasks: &[Task]) -> String` का ownership समझाएं।
सिर्फ इसी CLI का example लें।
`String`, `&str`, `Vec<Task>`, `&[Task]` को beginner-friendly भाषा में समझाएं।
अनावश्यक `clone()` न जोड़ें।

बहुत सामान्य गलती है कि हर borrow checker error को clone() से दबा दिया जाए। clone() कभी-कभी सही है, लेकिन उसका कारण होना चाहिए। यदि function केवल पढ़ता है, तो borrowing अधिक साफ design है।

Copy-paste CLI example

Core logic को src/lib.rs में रखें। इससे tests आसान होंगे और main.rs छोटा रहेगा।

// src/lib.rs
use anyhow::{Context, Result};
use std::{fs, path::Path};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Task {
    pub title: String,
    pub done: bool,
}

pub fn parse_tasks(input: &str) -> Vec<Task> {
    input.lines().filter_map(parse_task_line).collect()
}

fn parse_task_line(line: &str) -> Option<Task> {
    let trimmed = line.trim();

    if let Some(title) = trimmed
        .strip_prefix("[x] ")
        .or_else(|| trimmed.strip_prefix("[X] "))
    {
        return Some(Task {
            title: title.trim().to_string(),
            done: true,
        });
    }

    if let Some(title) = trimmed.strip_prefix("[ ] ") {
        return Some(Task {
            title: title.trim().to_string(),
            done: false,
        });
    }

    None
}

pub fn summarize(tasks: &[Task]) -> String {
    let total = tasks.len();
    let done = tasks.iter().filter(|task| task.done).count();
    let open = total.saturating_sub(done);

    format!("{total} tasks: {done} done, {open} open")
}

pub fn read_tasks(path: impl AsRef<Path>) -> Result<Vec<Task>> {
    let path = path.as_ref();
    let content = fs::read_to_string(path)
        .with_context(|| format!("failed to read {}", path.display()))?;

    Ok(parse_tasks(&content))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parses_markdown_style_tasks() {
        let tasks = parse_tasks("[ ] write parser\n[x] add tests\n[X] run clippy\n");

        assert_eq!(
            tasks,
            vec![
                Task {
                    title: "write parser".to_string(),
                    done: false,
                },
                Task {
                    title: "add tests".to_string(),
                    done: true,
                },
                Task {
                    title: "run clippy".to_string(),
                    done: true,
                },
            ]
        );
    }

    #[test]
    fn ignores_unrecognized_lines() {
        let tasks = parse_tasks("# Sprint notes\n- plain bullet\n[ ] keep this\n");

        assert_eq!(tasks.len(), 1);
        assert_eq!(tasks[0].title, "keep this");
    }

    #[test]
    fn summarizes_counts() {
        let tasks = parse_tasks("[ ] one\n[x] two\n[ ] three\n");

        assert_eq!(summarize(&tasks), "3 tasks: 1 done, 2 open");
    }
}

अब src/main.rs:

// src/main.rs
use anyhow::Result;
use clap::Parser;
use std::path::PathBuf;
use tasknote::{read_tasks, summarize};

#[derive(Parser, Debug)]
#[command(name = "tasknote", about = "Summarize simple task files")]
struct Cli {
    #[arg(short, long, default_value = "tasks.txt")]
    file: PathBuf,

    #[arg(long)]
    only_open: bool,
}

fn main() -> Result<()> {
    let args = Cli::parse();
    let tasks = read_tasks(&args.file)?;

    if args.only_open {
        for task in tasks.iter().filter(|task| !task.done) {
            println!("- {}", task.title);
        }
    } else {
        println!("{}", summarize(&tasks));
    }

    Ok(())
}

tasks.txt example:

[ ] write parser
[x] add unit tests
[ ] run clippy

Verification commands:

cargo fmt
cargo test
cargo clippy --all-targets -- -D warnings
cargo run -- --file tasks.txt
cargo run -- --file tasks.txt --only-open

यहां main Result<()> return करता है। अगर file missing है, तो anyhow::Context path के साथ error दिखा सकता है। CLI में missing input recoverable error है, इसलिए unwrap() से crash कराना अच्छा अनुभव नहीं है।

Tests, fmt और Clippy को task में शामिल करें

Claude Code को code के साथ verification भी करनी चाहिए।

`src/lib.rs` और `src/main.rs` implement करें।
Edit के बाद `cargo fmt`, `cargo test`, `cargo clippy --all-targets -- -D warnings` चलाएं।
यदि command fail हो, पहले error summarize करें, फिर सबसे छोटा reasonable fix करें।
Tests के बाहर `unwrap()` का उपयोग न करें।

Claude Code official docs के अनुसार codebase पढ़ सकता है, files edit कर सकता है और commands चला सकता है। फिर भी developer को git diff देखना चाहिए और यह confirm करना चाहिए कि scope के बाहर file नहीं बदली।

Practical use cases

पहला use case है existing Rust CLI में छोटा feature जोड़ना। जैसे --json output चाहिए, तो summarize को न बदलते हुए अलग JSON formatter बनवाएं।

दूसरा use case है ownership error सीखना। cannot move out of या borrowed value does not live long enough दिखे, तो पूरा error और function Claude Code को दें और पूछें कि कौन value own कर रहा है।

तीसरा use case है test-first bug fix। खाली line, [X], invalid line जैसे cases पहले tests में लिखें, फिर parser बदलें।

चौथा use case है safe refactoring। main.rs बड़ा हो जाए तो parsing, file I/O और output को अलग करें, लेकिन public function signatures न बदलें।

Common pitfalls

हर borrow error पर clone() न लगाएं। पूछें कि क्या borrowing काफी है।

Production CLI path में unwrap() न छोड़ें। Files, config और user input fail हो सकते हैं।

Tests के बिना refactor न करें। Claude Code बड़ा diff जल्दी बना सकता है, पर review कठिन हो जाता है।

Shared workspace में पूरे project पर formatting न चलाएं जब task केवल एक crate तक सीमित हो।

Safe refactor prompt

`tasknote` parser को safely refactor करें।

Constraints:
- `[ ] task` और `[x] task` का meaning न बदलें
- `parse_tasks`, `summarize`, `read_tasks` की public signatures न बदलें
- केवल `src/lib.rs` और उसके tests touch करें
- unnecessary `clone()` न जोड़ें
- पहले 3-line plan दें और approval का इंतजार करें

Edit के बाद:
- `cargo fmt`
- `cargo test`
- `cargo clippy --all-targets -- -D warnings`
- diff और ownership decisions summarize करें

यह prompt Claude Code को सीमाएं, checks और report format देता है। Rust के साथ यह तरीका अच्छा काम करता है, क्योंकि compiler, tests और Clippy जल्दी feedback देते हैं।

CTA और अगला कदम

Practice के लिए JSON output, CSV export, directory scan या serde format जोड़ें। Team में use करना हो तो Rust edition, required commands, unwrap() policy, allowed crates और review checklist CLAUDE.md में लिखें।

ClaudeCodeLab Claude Code prompts, templates, setup guides और team training देता है। पहले free cheatsheet देखें, फिर products and templates या repository-specific help के लिए training and consultation देखें। आगे TDD with Claude Code और review workflow checklist भी उपयोगी हैं।

Tested-result note: सबसे स्थिर flow यह रहा कि logic src/lib.rs में रहे, behavior cargo test से fix हो, और edit से पहले Claude Code ownership समझाए। इससे unnecessary clone() कम हुए और review करने लायक छोटा diff मिला।

#Claude Code #Rust #CLI #tests #refactoring
मुफ़्त

मुफ़्त PDF: Claude Code cheatsheet

Email डालें और commands, review habits तथा safe workflow वाली एक-page PDF पाएँ.

हम आपका data सुरक्षित रखते हैं और spam नहीं भेजते.

Masa

लेखक के बारे में

Masa

Claude Code workflow और team adoption पर काम करने वाला engineer.