🤔

Rubyさんの変数のスコープが思ってたんと違った

2025/03/04に公開

おはようございます、こんにちは、こんばんは。
スペースマーケットでWebエンジニアをしています、s0arです。

最近くしゃみやばいんですがこれ花粉すか?
自分外出自粛いいすか?

それはさておき、タイトルどおりの話です。
もう何年Rubyやってんすか?って感じなんですけどね。
いやー、マジか…ってなりました。

たとえばこういうコードがあるとするじゃないですか

i = 0
while i < 3
  x = i * 2
  i += 1
end

puts x

さて、puts xはどうなると思います?

「そらループ内で宣言されてるから、xは参照できんしエラーになるやろなあ…」
そんなふうに考えていた時期が俺にもありました

正解はこう!

puts x #=> 4

!!!???!?!??!?!?!wwwwwwwwww

…俺はプログラミングを忘れたのか…?
また「独習ナントカ」からやり直しなのか…?

いや、落ち着こう
せっかくだから、俺はこのコードをJavaScriptで書くぜ!

let i = 0;
while (i < 3) {
  let x = i * 2;
  i++;
}

console.log(x); // ReferenceError: x is not defined

そらそうよ
ワイのエンジニア人生は間違ってなかったんや

ほなRubyさんはなんでこんなことになってるんや?

Rubyさんはforやwhileなどの制御構造でスコープを作らない

どういうことだってばよ

つまりですね、Rubyの場合だいたいこんな感じ~

ループの種類 ループ外での変数の参照 説明
whileループなどの制御構造 可能 制御構造は新しいスコープを作成しない
eachメソッドなどのイテレータ 不可能 イテレータのブロックは新しいスコープを作成する

↑ではループに限定した話をしていますが、その他の制御構造についても同じ。
制御構造についての詳細はリファレンスをチェケラ

https://docs.ruby-lang.org/ja/latest/doc/spec=2fcontrol.html

ってことで、コードにするとこうなる

# while
while_count = 0
while while_count < 3
  while_x = while_count * 2
  while_count += 1
end
puts while_x #=> 4

# each
[0, 1, 2].each do |each_count|
  each_x = each_count * 2
end
puts each_x #=> NameError: undefined local variable or method `each_x'

ほえ~しらんかった…
なんでしらんかったんやろなあ…

いやまあ、ほら…大体こう書くよね…

i = 0
x = 0
while i < 3
  x = i * 2
  i += 1
end
puts x #=> 4

ループ外で参照したかったら、ループ外であらかじめ宣言してあげるよねっていう話

まとめ

お前がそう思うんならそうなんだろう
お前ん中ではな

って感じ
それでもループ入る前に宣言してあげるのが自然だよねと思いました。
あたまおかしなるで

GitHubで編集を提案
スペースマーケット Engineer Blog

Discussion