區塊轉發¶
要轉發捕獲的區塊,您可以使用區塊引數,在表達式前加上 &
def capture(&block)
block
end
def invoke(&block)
block.call
end
proc = capture { puts "Hello" }
invoke(&proc) # prints "Hello"
在上面的範例中,invoke
接收一個區塊。我們無法將 proc
直接傳遞給它,因為 invoke
不接收常規引數,只接收區塊引數。我們使用 &
來指定我們實際上想要將 proc
作為區塊引數傳遞。否則
invoke(proc) # Error: wrong number of arguments for 'invoke' (1 for 0)
您實際上可以將 proc 傳遞給一個會 yield 的方法
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
轉發。