「なぜ split $;, $_[1] なのかは宿題」の答え
まずは、問題。
1から100までの数をプリントするプログラムを書け。
http://www.aoky.net/articles/jeff_atwood/why_cant_programmers_program.htm
ただし3の倍数のときは数の代わりに「Fizz」と、5の倍数のときは「Buzz」とプリントし、3と5両方の倍数の場合には「FizzBuzz」とプリントすること。
弾さんの答え
tie my %fizzbuzz, 'Tie::Code' => sub { $_[0] % 15 ? $_[0] % 5 ? $_[0] % 3 ? $_[0] : 'Fizz' : 'Buzz' : 'FizzBuzz'; };print "$fizzbuzz{$_}\n" for (1..100);
答えは感嘆せざるをえないほど簡単だ。
package Tie::Code; use Tie::Hash; sub TIEHASH { bless $_[1], $_[0] } sub FETCH { $_[0]->( split $;, $_[1] ) }なぜsplit $;, $_[1]なのかは宿題ということで。
http://blog.livedoor.jp/dankogai/archives/50826956.html
そして、宿題の答えなのですが、わかりませんでした!
わかったのは、「split $;」しても、しなくても結果は同じになったということです。
$_[1]には1から100のスカラー値が設定されます。
そして「split $; $_[1]」すると配列値(ゼロ番目にそのスカラー値)になります。
しかし、これを受ける方(無名サブルーチン)で、第一引数の$_[0]になっていますので、スカラー値でも配列値も同じ値になりますよね。
実際、実行結果でも同じでした。
ちなみに、私的にソース解説をしときました。
tie my %fizzbuzz, 'Tie::Code' => sub { $_[0] % 15 ? $_[0] % 5 ? $_[0] % 3 ? $_[0] : 'Fizz' : 'Buzz' : 'FizzBuzz'; };
は、入れ子の3項演算子使用で、以下のようにすると意味が理解しやすくなります。
tie my %fizzbuzz, 'Tie::Code' => sub { $_[0] % 15 ? $_[0] % 5 ? $_[0] % 3 ? $_[0] : 'Fuzz' : 'Bumper' : 'FuzzBumper'; };
- 15で割れなくて、5で割れなくて、3で割れないと$_[0]をリターン値とする。
- 15で割れなくて、5で割れなくて、3で割れると'Fuzz'をリターン値とする。
- 15で割れなくて、5で割れると'Bumper'をリターン値とする。
- 15で割れると'FuzzBumper'をリターン値とする。
尚、「・・・ 'Tie::Code' => sub{ ・・・」等でハッシュぽっく書いてあるけど、この無名サブルーチンリファレンスは、コンストラクタ(Tie::CodeのTIEHASH)の第2引数にセットされる。
print "$fizzbuzz{$_}\n" for (1..100);
は、以下と同じです。
for $_ (1..100) { print "$fizzbuzz{$_}\n"; }