📌

変数と不変性 — Rubyの自由な再代入が消えた理由

let, mut, shadowing, const — Ruby変数と1:1比較

Rubyでx = 10と書けばx = 20にいつでも変えられる。Rustは違う。let x = 10;で宣言するとこの値は不変だ。変えようとするとコンパイルエラーになる。

let x = 10;
// x = 20;  // error[E0384]: cannot assign twice to immutable variable

Rubyのfreezeが全変数にデフォルト適用されたと思えばいい。

mut — 明示的な可変宣言

値を変えたければmutを付ける。

let mut x = 10;
x = 20;  // OK

「この変数は変わります」とコードを読む人に伝えるもの。Rubyでは全変数が暗黙的にmut。Rustは意図の明示を要求する。

shadowing — 同じ名前で再宣言

Rubyでx = "hello"x = 42になっても問題ない。型が変わってもいい。Rustでこれに近いのがshadowingだ。

let x = "hello";  // &str
let x = x.len();  // usize — 型が変わってもOK
let x = x + 1;    // 前のxを隠して新しいx

mutとの違い:shadowingは新しい変数を作ること。前のxにはもうアクセスできない。mut同じ変数の値を変えること。

// mutは型を変えられない
let mut x = "hello";
// x = 5;  // コンパイルエラー!型が違う

// shadowingは型も変わる
let x = "hello";
let x = 5;  // OK — 新しい変数

Ruby開発者にはshadowingの方が自然に感じるかもしれない。実際のRustコードでもよく使う。特に文字列をパースして数値に変換する時、同じ名前を再利用するパターンが一般的だ。

const — RubyのCONSTANT

RubyのMAX_SIZE = 100のように定数を宣言する時はconstを使う。

const MAX_SIZE: usize = 100;

letとの違い:

  • const必ず型を明示する必要がある

  • constはコンパイル時に値が決まる(ランタイム計算不可)

  • constはどこでも使える(関数の外でもOK)

Rubyでは定数に再代入すると警告が出るが実行はされる。Rustではconstの再代入は不可能。

まとめ

Ruby Rust 説明
x = 10 let x = 10; 不変
x = 10; x = 20 let mut x = 10; x = 20; 可変
x = "hi"; x = 42 let x = "hi"; let x = 42; shadowing
MAX = 100 const MAX: usize = 100; 定数

キーポイント

1

letはデフォルト不変 — Rubyのfreezeがデフォルトのようなもの

2

mutを付ければ可変 — Rubyでは全変数が暗黙的にmut

3

shadowingは同じ名前で新変数を作る — 型も変えられる

4

constはコンパイル時定数 — RubyのCONSTANTより厳格

メリット

  • 不変デフォルトのおかげで意図しない値の変更が根本から遮断される
  • shadowingでRubyのように柔軟な変数再利用が可能

デメリット

  • 習慣的にmutを付けがちだが、可能なら不変にするのがRust慣例
  • shadowingを乱用すると同じ名前の変数が異なる値を持ち混乱

ユースケース

不変データを扱う時 — 設定値、計算結果など 型変換時のshadowing — パース結果を同じ名前で