あどけない話

インターネットに関する技術的な話など

Rubyのローカル変数

Ruby のローカル変数の仕様が、さっぱり分らず、いろんな文献/ページや、実験をしてみてようやく分りました。

注:これは、Ruby ではどう書くべきかということではなく、仕様はどうなっているのかという話です。

スコープ

Ruby 書籍には、ローカル変数には以下のスコープがあると書かれています。

  • メソッド
  • クラス
  • モジュール
  • ブロック

しかし書籍には、プログラムのトップレベルに、いきなりローカル変数が現れます。

x = 1 # トップレベル
puts x # => 1

よくよく調べてみると、トップレベルというスコープもあるそうです。だったら、はじめからこう書くべきではないですか?

Ruby の変数には、以下のスコープがあります。

  • メソッド
  • クラス
  • モジュール
  • ブロック
  • トップレベ

ブロック

あるスコープからは、外側のスコープのローカル変数は見えません。なので、あるスコープで、あるローカル変数に代入すると、新しいローカル変数が定義されたことになります。

x = 1 # トップレベル
def foo()
  x = 2 # メソッド
end
foo()
puts x # => 1

Ruby の書籍には、begin/end にも do/end にもブロックという言葉が使われています。スコープで言うブロックとは、do/end です。

1.times do
 x = 0 # ブロックレベル
end
p x # トップレベルには x がないのでエラー

スコープの視点からすると、begin/end ではありません。

begin
 x = 0 # 単なるトップレベル
end while false
p x # => 0

さて、do/end のブロックからは、例外として外のスコープが見えます。

1.times do
 x = 0 # ブロックレベル
 1.times do
   x = 1 # 外のブロックレベル
 end
 puts x # => 1
end

do/end ブロック内に、外のスコープにあるローカル変数名を使って、別の新たなローカル変数は定義できないようです。

感想

Ruby のローカル変数は分りにくいです。その要因は、以下のようなことでしょう。

  • ちゃんとした説明を発見できない
  • 宣言なしで変数を使う思想
  • ブロックに例外がある
    • スコープから見ると do/end がブロックで、begin/end はブロックではない
    • do/end ブロックからは、外のスコープが見えるという例外がある

勘違いがあれば、指摘して下さい。(_ _)