所有的”方法(methods)”隐式跟上一个”块(block)”参数。
块参数也可以明确给定,形式就是在参数前面加一个”&”,比如 def fn(arg1, arg2, &block) end,其中的 &block 就是明确给定的块参数。
块参数的动作,可以通过调用 call() 方法执行,还可以用 yield 来执行 —— yield 其实就是一个语法糖。
所以以下几种写法常常是等价的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| def foo yield 1 end
def foo2(&block) yield 1 end
def foo3(&block) block.call(1) end
foo1 {|x| puts x} foo2 {|x| puts x} foo3 {|x| puts x}
|
Proc
前面说到所有方法都可以隐式或显式指定一个块参数,那么块参数到底是什么呢?
答案是 Proc 对象,一个具有 call 方法的对象。
Proc 对象的定义有几种形式:
- 直接使用 {}
- 使用 Proc.new {}
- 使用 proc {}
- 使用 lambda {}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| def foo(&block) puts block.class puts block.to_s yield 1 end
foo {|x| puts x}
my_proc = proc { |n| puts n } foo(&my_proc)
my_proc = Proc.new { |n| puts n } foo(&my_proc)
my_proc = lambda { |n| puts n } foo(&my_proc)
|
yield self
在一个对象中,self 表示是一个当前对象的引用。
所以,常见的 yield self if block_given? 中的 self 就和其它地方使用 self 一样,没什么特殊的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| class C1 def foo(&block) puts block.class puts block.to_s yield self if block_given? yield "AAAAAAAAA" end end
class C2 def foo(&block) puts block.class puts block.to_s yield self if block_given? yield "BBBBBBBBB" end def to_s "XXXXXXXXXX" end end
c1 = C1.new c1.foo {|x| puts x}
c2 = C2.new c2.foo {|x| puts x}
|
注意事项
method 定义中 &block 参数必须在最后
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| def foo(arg1, arg2, &block) puts block end
block = proc {|x| puts x} foo( 1, 2, &block)
def foo(arg1, &block, arg2) puts block end
|
yield 相当于是 block.call() 方法的调用,所以参数个数也需要对应
1 2 3 4 5 6 7 8
| def foo() yield 1,2,3 end
foo {|x| puts x} foo {|x,y,z| puts z} foo {|x,y,z,k| puts k}
|
prev
last update time 2022-05-06
next