ブロックのdo〜endは制御構造に、{}は式に
{ } と do end の違い - gan2 の Ruby 勉強日記
require 'benchmark' puts Benchmark::CAPTION puts Benchmark.measure { a = [1, 2, 3] a.replace [4, 5, 6] } このように { } を使うのは OK なのに { } を do end に変えると require 'benchmark' puts Benchmark::CAPTION puts Benchmark.measure do a = [1, 2, 3] a.replace [4, 5, 6] end `measure': no block given (LocalJumpError) ってエラーが出る。
そう、ふたつのブロック構文{}とdo〜endの優先順位の違い。
「puts Benchmark.measure do 〜 end」はKernel#putsにBenchmark.measureという引数とブロックを渡していると解釈される。だからBenchmark.measureにブロックがないぞーっと怒られる。
一般にdo〜endは制御構造…つまり、返り値は使わない副作用のみ利用する場合に使うとよい。Integer#timesやeachメソッドなんかがいい例。まあ俺ならブロックが1行ならば{}を使うけどそのへんは好みで…
3.times do |i| puts i end # >> 0 # >> 1 # >> 2
対してEnumerable#map等のように返り値を使うブロック付きメソッドは{}を使おう。返り値を使うということは、「式」として見ているので、{}の方が式らしく見える。Rubyは美観にこだわっている。
a = [1,2,3] puts a.map {|x| x*3 } # >> 3 # >> 6 # >> 9
こっちだと明らかに「a.map {|x| x*3}」がputsの引数になっているよね。さきほどのBenchmark.measureも同じこと。
ちなみに{}とdo〜endの問題が顕著になるのはRakefileだ。taskメソッドに:hogehogeという引数とブロックを渡すコードは
task :hogehoge do puts "hogehoge" end
と書くけれど、
task :hogehoge { puts "hogehoge" }
こっちはSyntaxErrorになる。
追記
スーパーPRE記法、使ってみます。素のw3mでブラウジングしています。
Emacs Lisp書かなくては…