標籤:
yield
所有的"方法(methods)"隱式跟上一個"塊(block)"參數。
塊參數也可以明確給定,形式就是在參數前面加一個"&",比如 def fn(arg1, arg2, &block) end,其中的 &block 就是明確給定的塊參數。
塊參數的動作,可以通過調用 call() 方法執行,還可以用 yield 來執行 —— yield 其實就是一個文法糖。
所以以下幾種寫法常常是等價的:
#method receives an invisible block argumentdef foo1() yield 1end#specify it explicitlydef foo2(&block) yield 1end#yield is equal to block.calldef foo3(&block) block.call(1) end#function callfoo1 {|x| puts x} # => 1foo2 {|x| puts x} # => 1foo3 {|x| puts x} # => 1
Proc
前面說到所有方法都可以隱式或顯式指定一個塊參數,那麼塊參數到底是什麼呢?
答案是 Proc 對象,一個具有 call 方法的對象。
Proc 對象的定義有幾種形式:
- 直接使用 {}
- 使用 Proc.new {}
- 使用 proc {}
- 使用 lambda {}
#yield is equal to block.calldef foo(&block) puts block.class puts block.to_s yield 1 end#function call# Proc created using {} syntaxfoo {|x| puts x} # => Proc# => #<Proc:[email protected](ruby):9># => 1# Proc created with the "proc" keyword. Note & syntax when calling.my_proc = proc { |n| puts n }foo(&my_proc)# => Proc# => #<Proc:[email protected](ruby):12># => 1# Proc creates with Proc.newmy_proc = Proc.new { |n| puts n }foo(&my_proc) # => 1# => Proc# => #<Proc:[email protected](ruby):16># => 1# Proc created with the "lambda" keyword. Nearly same thing.my_proc = lambda { |n| puts n }foo(&my_proc)# => Proc# => #<Proc:[email protected](ruby):20 (lambda)># => 1
yield self
在一個對象中,self 表示是一個當前對象的引用。
所以,常見的 yield self if block_given? 中的 self 就和其它地方使用 self 一樣,沒什麼特殊的。
class C1 def foo(&block) puts block.class puts block.to_s yield self if block_given? yield "AAAAAAAAA" endendclass C2 def foo(&block) puts block.class puts block.to_s yield self if block_given? yield "BBBBBBBBB" end def to_s "XXXXXXXXXX" endendc1 = C1.newc1.foo {|x| puts x}# => Proc# => #<Proc:[email protected](ruby):23># => #<Context::C1:0x00000001c84af0># => AAAAAAAAAc2 = C2.newc2.foo {|x| puts x}# => Proc# => #<Proc:[email protected](ruby):26># => XXXXXXXXXX# => BBBBBBBBB
注意事項
method 定義中 &block 參數必須在最後
# 正確樣本def foo(arg1, arg2, &block) puts blockend#function callblock = proc {|x| puts x}foo( 1, 2, &block) # => #<Proc:[email protected](ruby):14>#錯誤樣本def foo(arg1, &block, arg2) # => (ruby): syntax error puts blockend
yield 相當於是 block.call() 方法的調用,所以參數個數也需要對應
def foo() yield 1,2,3 # 這裡的 1 2 3 就是傳遞的參數end#function callfoo {|x| puts x} # => 1foo {|x,y,z| puts z} # => 3foo {|x,y,z,k| puts k} # 為空白
ruby 疑痛點之—— yield 和 yield self