🐰

Ruby ブロックのDocsを読んだだけ

に公開

普段なんとなくで書いていたが、改めて考えると、do end とか、Blockって何・・・?となってしまったので、調べてみる。

[引用]
https://docs.ruby-lang.org/ja/latest/doc/spec=2fcall.html#block

ブロックとは?

do ... end または { ... } で囲まれたコードの断片 (ブロックと呼ばれる)

なるほど、do ... end か { ... } で囲んだコードのことか。
コードの断片?断片なのか。

{ ... } の方が do ... end ブロックよりも強く結合します。次に例を挙げますが、このような違いが影響するコードは読み辛いので避けましょう:

強く結合ってなんだろう。

ブロックの中で初めて代入された(宣言された)ローカル変数はそのブロックの中でだけ有効です。例えば:

foobar {
  i = 20                # ローカル変数 `i' が宣言された
  # ...
}
print defined? i        # `i' はここでは未定義なので false
foobar a, b do
  i = 11                # まったく別の変数 i の宣言
  # ...
end

ブロックがスコープになると。
defined?なんてあるんだ笑

ブロックの部分だけを先に定義して変数に保存しておき、後からブロック付きメソッドに渡すことも出来ます。それを実現するのが手続きオブジェクト(Proc)です。
それをブロックとして渡すにはブロック付きメソッドの最後の引数として `&' で修飾した手続きオブジェクトを渡します。
Proc の代わりにメソッドオブジェクト(Method)を渡すことも出来ます。この場合、そのメソッドを呼ぶ手続きオブジェクトが生成され渡されます。

# 1引数の手続き(その働きは引数をpで印字すること)を生成し、変数pobjに格納
pobj = proc {|v|
  p v
}

[1,2,3].each(&pobj) # 手続きオブジェクトをブロックの代わりに渡している
# => 1
#    2
#    3

ほー!!Procを使えば、後からブロック付きメソッドに渡せるのか!
それには、&をつける必要があると。

&なしだとどうなるか試してみる。

pobj = proc {|v|
  p v
}

[1,2,3].each(pobj) # &なしで渡してみる
# => app/test.rb:6:in 'Array#each': wrong number of arguments (given 1, expected 0) (ArgumentError)

ほぅ、ArgumentErrorになった。

to_proc メソッドを持つオブジェクトならば、`&' 修飾した引数として渡すことができます。
デフォルトで Proc、Method オブジェクトは共に to_proc メソッドを持ちます。
to_proc はメソッド呼び出し時に実行され、Proc オブジェクトを返すことが期待されます。

class Foo
  def to_proc
    Proc.new {|v| p v}
  end
end
[1,2,3].each(&Foo.new)
# => 1
#    2
#    3

へぇ!to_procをはやせば、こんな感じで渡せるようになるのか!!

Discussion