Rubyのスコープと変数定義で「What!?」ってなった話
最近になって急に、開発言語がPerlからRubyとObjective-Cに早変わりして大変です。
そして、Perlの感覚でRubyを書いていると「What!?」ってなったことがあったので、
久しぶりに記事にしてみました。
下記はPerlのコードです。
#!/usr/bin/env perl use strict; use warnings; use utf8; if (0) { my $message = 'hoge'; } print "$message\n";
が、当然エラーは出ます。
Global symbol "$message" requires explicit package name at.. Execution of.. aborted due to compilation errors.
message変数のスコープがIfブロック内なので当たり前ですよね。
下記はRubyのコードです。
#!/usr/bin/env ruby if false message = 'hoge' end puts "#{message}"
が、エラーは出ません
(何も表示されない)
どうやら、RubyにおいてIfやFor,Whileブロックはスコープを生成しないらしいです。
Ruby
#!/usr/bin/env ruby hoge = 10 puts hoge if true hoge = 100 puts hoge end puts hoge
10 100 100
Perl
#!/usr/bin/env perl use strict; use warnings; use utf8; my $hoge = 10; print "$hoge\n"; if (1) { my $hoge = 100; print "$hoge\n"; } print "$hoge\n";
10 100 10
それでは、話を下記のコードに戻します。
#!/usr/bin/env ruby if false message = 'hoge' end puts "#{message}"
さて、Ifブロックがスコープを生成しないため、Ifブロック外で変数が見えていることは分かりましたが、
何故、undefined local variable or method
エラーが出ない理由が分かりません。
実際にmessage変数のクラスを表示するとNilClassになっています。
#!/usr/bin/env ruby if false message = 'hoge' end puts "#{message.class}";
NilClass
理由は簡単で、ちゃんと定義されているからです。
どうも、Rubyのパーサは代入を見つけた時点で、勝手に変数を定義するようになっているそうです。
知っていれば当たり前なのかも知れませんが、
慣れていない自分からすると、
初期化されていない気がして不安になってしまいます(||゚Д゚)ヒエー!!
参考URL