🚽 うんちで覚えるRust入門 〜所有権は「今ここにある💩はひとつだけ」〜
はじめに
Rustを勉強し始めました。
所有権・借用・ライフタイム……なんだか難しそうでとっつきにくい。
でもある日、ふと気づきました。
「トイレに落ちたうんちの所有権は、いったい誰にあるのか?」
この哲学的な問いをきっかけに、Rustのすべてを「うんち」で説明できることに気づいてしまったのです。
子供たちに大人気の「うんこドリル」にあやかって、ここに 「うんちドリル式 Rust講座」 を開講します。
💩 大原則
「うんちは世界に1つだけ。あなたがしたうんちは唯一無二。今この場にうんちは1つしか存在しない。」
この原則さえ覚えれば、コンパイラのエラーが
「あ、今うんちのルール破ったわ」 と読めるようになります。
目次
- 環境構築
まずはトイレ(開発環境)の準備です。
Windowsの場合
- Visual Studio Build Tools をインストール(「C++ によるデスクトップ開発」にチェック)
- rustup.rs からインストーラを実行
- VS Codeに
rust-analyzer拡張機能を入れる
動作確認
cargo new hello_unchi
cd hello_unchi
cargo run
Hello, world! が出れば準備完了です。
- 所有権(最重要)
💩 うんち理論 基本の「き」
rust
let a = String::from("💩"); // aさんが💩を所有
let b = a; // 💩がbさんに移動 (Move)
println!("{}", a); // ❌ コンパイルエラー! aさんはもう💩を持っていない
Pythonなら a も b も使えますが、Rustは違います。
「💩をbにあげたのに、aの手を見ようとしてる。それはないよ。」とコンパイラに怒られます。
なぜそんな厳しいルールが?
Rustには トイレの自動洗浄機能 がついています。
所有者(💩を持っている人)がスコープを抜けると、自動で流れる(=メモリ解放) のです。
もし所有者が2人いたら?
→ 「俺が流す」「いや俺が流す」で 二重解放バグ が起きます。
だからRustは 「💩を持つのは常に1人だけ」 というルールを課しているのです。
cloneでコピーする
どうしても2つ必要なら、clone() で うんちを複製 します(ただしメモリは2倍)。
rust
let a = String::from("💩");
let b = a.clone(); // 複製したので、aもbも使える
- 借用
「複製はメモリがもったいない。ちょっと見たいだけなのに…」
そんなときは 「借用」 です。& をつけます。
rust
let a = String::from("💩");
let b = &a; // bは「見るだけ」借りた
println!("a: {}", a); // ✅ aはまだ持ってる
println!("b: {}", b); // ✅ bは見てるだけ
借用のルール(衛生管理規定)
種類 記号 ルール
不変参照 &T 見るだけ。何人同時に見てもOK
可変参照 &mut T 加工できる。でも同時に1人だけ。加工中は持ち主も触れない
rust
let mut a = String::from("💩");
let b = &mut a; // bが「加工するね」と借りた
b.push_str("🍓"); // イチゴをトッピング
// println!("{}", a); // ❌ 今はbが独占中。持ち主のaも見れない
println!("{}", b); // ✅ 💩🍓
- StringとStr
Rustには文字列型が2つあります。これもうんちで説明できます。
型 うんちで例えると 特徴
&str 石に彫ったうんち 変えられない。メモリ固定。所有権の移動が起きない
String ホワイトボードのうんち 書き換え自由。メモリを確保する。所有権が移動する
rust
let a = "💩"; // &str (石に彫ったやつ)
let b = String::from("💩"); // String (消して書けるやつ)
- AxumでAPIサーバー
理論がわかったところで、うんち株価API を作ってみましょう。
Cargo.toml
toml
[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
main.rs(完成形)
rust
use axum::{Router, routing::get, Json, extract::Path};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct StockResponse {
symbol: String,
price: f64,
message: String,
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/health", get(health_handler))
.route("/stock/:symbol", get(stock_handler));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
println!("🚀 サーバー起動: http://localhost:3000");
axum::serve(listener, app).await.unwrap();
}
async fn health_handler() -> Json<serde_json::Value> {
Json(serde_json::json!({
"status": "ok",
"message": "🚽 トイレは正常稼働中"
}))
}
async fn stock_handler(Path(symbol): Path<String>) -> Json<StockResponse> {
let response = StockResponse {
symbol: symbol.to_uppercase(),
price: 185.50,
message: format!("{}の💩は絶好調です", symbol.to_uppercase()),
};
Json(response)
}
cargo run して http://localhost:3000/stock/AAPL にアクセスすれば、あなたのAPIサーバーが動き出します。
- Cargo.tomlの読み方
Pythonの requirements.txt に相当します。Rustは cargo run 一発で依存関係の解決からビルド、実行までやってくれます。
toml
[dependencies]
axum = "0.7" # Webフレームワーク
tokio = { version = "1", features = ["full"] } # 非同期ランタイム(電源)
serde = { version = "1", features = ["derive"] } # JSON変換
- 次のステップ
これであなたは 「うんち所有権マイスター」 です。
次は以下のステップに進みましょう。
✅ 可変借用(&mut)をマスターする
✅ Result型でエラーハンドリング(トイレが詰まったときの処理)
✅ Arc> で「公衆トイレの鍵」を実装する(複数人で安全に💩を共有)
おわりに
Rustのコンパイラは厳しいですが、それはあなたのコードを衛生的に保つ 便座洗浄機 のようなものです。
エラーが出ても怒らないでください。
「あ、今うんちを落としそうになったな」と優しく教えてくれているだけです。
「うんちは世界に1つだけ」
この言葉を胸に、快適なRustライフを送ってください。
Happy Coding! 🚽💩