ブロック転送¶
キャプチャされたブロックを転送するには、式に&
をプレフィックスとして付けたブロック引数を使用します。
def capture(&block)
block
end
def invoke(&block)
block.call
end
proc = capture { puts "Hello" }
invoke(&proc) # prints "Hello"
上記の例では、invoke
はブロックを受け取ります。invoke
は通常の引数ではなく、ブロック引数のみを受け取るため、proc
を直接渡すことはできません。&
を使用して、proc
をブロック引数として渡すことを明示的に指定します。それ以外の場合は
invoke(proc) # Error: wrong number of arguments for 'invoke' (1 for 0)
実際には、yieldするメソッドにprocを渡すことができます。
def capture(&block)
block
end
def twice(&)
yield
yield
end
proc = capture { puts "Hello" }
twice &proc
上記は単に書き直されたものです。
proc = capture { puts "Hello" }
twice do
proc.call
end
または、&
と->
構文を組み合わせます。
twice &->{ puts "Hello" }
または
def say_hello
puts "Hello"
end
twice &->say_hello
キャプチャされていないブロックの転送¶
キャプチャされていないブロックを転送するには、yield
を使用する必要があります。
def foo(&)
yield 1
end
def wrap_foo(&)
puts "Before foo"
foo do |x|
yield x
end
puts "After foo"
end
wrap_foo do |i|
puts i
end
# Output:
# Before foo
# 1
# After foo
&block
構文を使用してブロックを転送することもできますが、その場合は少なくとも入力型を指定する必要があり、生成されたコードにはクロージャが含まれ、速度が低下します。
def foo(&)
yield 1
end
def wrap_foo(&block : Int32 -> _)
puts "Before foo"
foo(&block)
puts "After foo"
end
wrap_foo do |i|
puts i
end
# Output:
# Before foo
# 1
# After foo
yield
で十分な場合は、このようなブロックの転送を避けてください。また、キャプチャされたブロック内ではbreak
とnext
は許可されないため、&block
転送を使用している場合、以下は機能しません。
foo_forward do |i|
break # error
end
要約すると、yield
が関与している場合は、&block
転送を避けてください。