Rustを始めることにした
30代未経験から始めたRustの旅
きっかけ:AIの時代とプログラミングの変化
AIの時代が来て、プログラミングの勉強が変わったと聞いた。「設計を学ぶことが人間にできる事だ」という話をいくつか見て、自分にも興味が湧いた。
ただ、設計を学ぶにしても、何を書いているか理解しないといけない。そこで「プログラミング言語を学ぶ必要がある」のに「AIがコードを書けるようになった」という矛盾を感じた。これがRustを始めるきっかけの最初の芽になった。YouTube Channell WIRED,WIRED.jpこの動画の影響もあると思う。
なぜJavaScriptを選んだか、そしてなぜ離れたか(厳密には離れてないけど
最初はPythonかなと思っていたが、「フロントもできなきゃな」と思ってJavaScriptを選んだ。Jonas(Udemy講師)の動画で勉強を始め、Node.jsもざっくり理解していった。
しかし、ある時点で強い違和感を感じた。
const fs = require('fs');
これで突然ファイルシステムのメソッドが使えるようになる。でも、何が起きているのか全然わからない。「使い方」は学べるが「仕組み」は見えない。このブラックボックス感が強くなっていった。
興味の方向性に気づいた
勉強していくうちに、自分の興味がどこにあるかが見えてきた。
- ターミナルが好きだった。かっこいいし(WezTermのような高品質なツールに惹かれた)
- ネットワークの仕組みに興味があった
- ファイルシステムの中身を知りたかった
- 「裏側を知りたい」という強い欲求がある。スッキリしたい
JavaScriptでは、これらの興味に答えられないと感じた。
なぜRustか
いくつかの言語を比較していくうちに、Rustに惹かれていった。
エラーメッセージが親切だった。 最初に体験したエラーは:
error[E0384]: cannot assign twice to immutable variable `x`
--> src/main.rs:4:5
|
2 | let x = 5;
| - first assignment to `x`
4 | x = 6;
| ^^^^^ cannot assign twice to immutable variable
|
help: consider making this binding mutable
|
2 | let mut x = 5;
| +++
エラーの場所、理由、そして答えまで出してくれる。JavaScriptのように動いてから「えっ?」になることがない。
「明示的であること」が好きだった。
JavaScriptは暗黙で動くことが多い。Rustは「何が起きているか」を全て明示的にする。
let x = 5; // 不変(デフォルト)
let mut x = 5; // 変更可能にする(明示的)
let s2 = s1; // 所有権移動(明示的)
let s2 = s1.clone(); // コピー(明示的)
let s2 = &s1; // 借用(明示的)
「何が起きているか」が常に見える。これが「ブラックボックス嫌」という自分の感覚に合っていた。
AI時代との関連
もう一つ大きな理由があった。AIの発展で、フロントエンドを自分で作る必要がかなり減っていきそうだと感じた。きっと最先端の意味ではそうではないのかもしれないが、一流になんか到底足元も及ばない…
最初にJavaScriptを選んだのは「フロントもできなきゃな」という理由だった。でも今や、そこの優先度が下がっている。
自分が本当にやりたいのは「バックエンドシステムの裏側」だと気づいた。メール処理、データ抽出、通知送信、予約管理のような「見えないところ」を作りたい。そこにはRustが合っていた。
環境をセットアップ
インストールは驚くほど簡単だった。
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
nvimにrust-analyzerを導入し、すぐに開発環境が整った。rust-analyzerのおかげで、ファイルを開くだけでリアルタイムにチェックが走る。
最初のプロジェクト:
cargo new hello-rust
cd hello-rust
cargo run
# Hello, world!
学んだこと
型とスカラー
JavaScriptとは違い、全てに型がある。でもデフォルトは覚えるだけでいいとClaudeに言われてしまった…。
整数 → i32
小数 → f64
正の整数 → u32
変数と不変性
デフォルトで変えられない。変えたいなら明示的にmutを言う。
let x = 5; // 変えられない
let mut x = 5; // 変えられる
スコープと死の時点
{}で生き死にが決まる。これがRustの根本だと感じた。
let x = 5;
{
let x = x * 2;
println!("{}", x); // 10
} // 内側のxはここで死ぬ
println!("{}", x); // 5に戻る
shadowing
新しい変数として上書きできる。古い値は消え、新しい値が積まれる。
let x = 5;
let x = x + 1; // エラーにならない、新しいxを作る
スタックとヒープ
スタック → 小さい、固定サイズ、速い(プリミティブ)
ヒープ → 大きい、動的サイズ(Stringなど)
最初は「プリミティブはスタック、オブジェクト的なものはヒープ」という感覚でJSと同じように理解した。
その後、調べて正確にわかったこと:
JSでも実際にプリミティブはスタック、オブジェクトはヒープに格納されている。ただし、これはJavaScriptの仕様ではなく、V8エンジン(Node.jsやChromeが使用)の実装の話である。つまり「仕様で決まっている」のではなく「エンジンがそう実装している」という点が違った。
また、オブジェクトの場合、実体はヒープに格納されるが、その参照(アドレス)はスタックに格納される。つまりスタックとヒープの両方が使われている。
間違っていたこと: 最初に「JSでも同じ感覚で大丈夫」と思っていたが、実際にはJSのスタック/ヒープの動きは開発者には見えない部分であり、エンジンの実装に依存している。Rustのように明示的に意識できる言語とは根本的に異なる。
GCとの違い:
メモリの掃除の仕組みも大きく異なる。
JavaScript(GC = ガベージコレクション)
→ エンジンが「もう使われない」と判断したら自動で掃除
→ いつ掃除されるか開発者には見えない
→ ヒープの管理は全てエンジン任せ
Rust(所有権によるメモリ管理)
→ スコープを出た時に即座に解放される
→ いつ死ぬかが見える
→ GCは存在しない
これが「ブラックボックス感」の大きな原因の一つだった。JSでは「なぜメモリが使われているのか」「いつ解放されるのか」が見えないが、Rustでは全て見える。
所有権(Ownership)
Rustの面白いところ、というかJSで散々悩んでいたところがスッキリした瞬間だった。データの「持ち主」が一つだけに決まる。
let s1 = String::from("hello");
let s2 = s1; // データは動いていない。持ち主がs1からs2に変わっただけ
// s1はもう使えない
「ムーブ」とは「データは動かず、持ち主だけ変わった」ということに気づいた。
三つの選択肢
// 1. 移動(s1死ぬ)
let s2 = s1;
// 2. クローン(データを複製)
let s2 = s1.clone();
// 3. 借用(データ共有)
let s2 = &s1;
関数と所有権
関数に値を渡すのは代入と同じ。所有権が関数へ移動する。
fn takes_ownership(s: String) {
println!("{}", s);
} // sはここで死ぬ
fn main() {
let s = String::from("hello");
takes_ownership(s); // sの所有権が関数へ移動
// もうsは使えない
}
戻り値で所有権を「返す」こともできる。
fn gives_ownership() -> String {
let s = String::from("hello");
s // 所有権を呼び出し元に返す
}
fn main() {
let s1 = gives_ownership(); // s1が所有権を受け取る
}
今後の目標
最終的に作りたいのは、このような仕組みだと今のところ考えている。
[ユーザー/モバイル]
↓
[Rust: リクエスト受信・処理]
↓
[Rust: データ抽出・加工]
↓
[データベース / 通知先]
メール処理や通知システム、予約管理のような「裏側」を、仕組みを理解した上で作りたい。
Rust Bookの第20章では、低レベルのマルチスレッドWebサーバーを実装するプロジェクトがあるみたいで。ネットワーク通信の仕組みも、そこで少しでも理解が進めばいいなと期待を膨らませている。
学習のスタイル
- Rust Book(日本語版) → 理解の深さ
- YouTube動画(Rust集中講座) → 視覚的な理解
- Jonas(JS) → 気分転換として続ける
「つまった」と感じたら、その理由をメモして後に振り返る。Rustのコンパイラが「なぜ」を詳しく出力するので、エラーと格闘というより、エラーを吸収していこうかなと思います。