読者です 読者をやめる 読者になる 読者になる

PerlerのRuby日記

Rubyとか

ローカル変数をスコープ内側へ

Ruby

Perlだとこれは動く。

my $outer = 123;

sub hoge {
  print "$outer\n";
}

hoge(); #=> 123

Perlは内側への変数スコープは有効だからだ。


対してRubyは動かない。

outer = 123

def hoge
  puts outer
end

hoge()
#=> NameError: undefined local variable or method `outer' for main:Object

最初はこれに驚いた。

いまメタプログラミングRubyを読んでいるのだけれど、ここに詳しく書かれていた。

スコープゲート


プログラムがスコープを切り替えて、新しいスコープをオープンする場所は3つある。


・クラス定義

・モジュール定義

・メソッド呼び出し


クラスやモジュールの定義、あるいはメソッドに出入りすると、スコープは変化する。この3つの境界線は、class、module、defといったキーワードで印がつけられている。3つのキーワードはそれぞれスコープゲートのように振る舞う。

(P.115)

上記の例だと、defでスコープがouter変数のいるスコープから切り替わるため、def hoge内でアクセスできない仕様ということらしい。


で、だがしかし、とは言うものの、外側の変数を簡単に参照したい場合もある。

(一番簡単なのはグローバル変数を使うことだろう。)


メタプログラミングRubyでは、スコープが切り替わらない、「ブロック」を利用して外側の変数を参照している例が載っていた。

ブロックは、ブロックが作成された時点での変数スコープが有効になるので、それを利用している。これはすごいなーと思った。

outer = 123

# トップレベルでdefine_methodを呼び出す
Kernel.send :define_method, :hoge do
  puts outer
end

hoge() #=> 123

よくできてるなー。


メタプログラミングRuby

メタプログラミングRuby