class Array
def iterate!(&code) #注意这里用了&符号
self.each_with_index do |n,i|
self[i] = code.call(n)
end
end
end
arr = [1,2,3,4]
arr.iterate! do |n|
n ** 2
end
#[1, 4, 9, 16]
今天读代码的时候,被这个&符号给蒙住了。ruby语言中时不时蹦出各种奇怪的符号,而且作用不明。还不好查得。
于是认真研究了一下。
&操作符的真正含义:proc对象和块之间的切换符号。&code 这是一个块, code 这是一个proc对象。简单的去掉&操作符,我们就能再次得到一个Proc对象。
===================================================
呃,其实如果没有上下文,完全说不清楚这段。还是看下面的例子吧,运行一趟就知道了。
def math_by_anonymouse_block(a,b)
yield a,b
end
def math_by_proc(a,b,a_proc)
a_proc.call(a,b)
end
def math_by_named_block(a,b,&namedblock)
puts "math_by_proc a,b,namedblock"
puts namedblock.class # &namedblock 是一个区块,namedblock (去掉&)是一个proc,&操作符是个切换开关。
puts math_by_proc a,b,namedblock
puts "======="
#lambda
mylambda = lambda &namedblock
puts mylambda.class
puts math_by_anonymouse_block a,b,&mylambda
#哈哈,下面这样也可以
puts "math_by_proc a,b,mylambda"
puts math_by_proc a,b,mylambda
puts "======="
#proc
myproc = proc &namedblock
puts myproc.class
puts math_by_anonymouse_block a,b,&myproc
#哈哈,下面这样也可以
puts "math_by_proc a,b,myproc"
puts math_by_proc a,b,myproc
puts "======="
#puts &namedblock.class
#区块不能直接赋值给一个变量。但是可以通过方法来传递
#myblock = &namedblock #运行不通
#puts myblock.class
#所以我们用这种方式
puts "math_by_anonymouse_block"
puts math_by_anonymouse_block a,b,&namedblock
puts "======="
end
math_by_named_block(2,3) {|x,y| x*y}
运行结果:
---------- ruby run ----------
math_by_proc a,b,namedblock
Proc
6
=======
Proc
6
math_by_proc a,b,mylambda
6
=======
Proc
6
math_by_proc a,b,myproc
6
=======
math_by_anonymouse_block
6
=======
输出完成 (耗时 0 秒) - 正常终止
区块就像是方法的额外匿名参数,任何方法在调用时,都可以在后面跟一个区块。只不过如果这个方法中有yield语句,它就会调用区块,如果没有yield语句,就无视这个区块。
比如:
def my_noyield
puts "leave me alone. no yield !"
end
def my_yield
puts "I call you! come on"
yield
end
my_noyield { puts "I'm coming!"}
my_yield { puts "I'm coming!"}
这是我们来定义一个带&操作符参数的方法,这就等于把之前的匿名参数变成了一个 &变量名 的参数。这个参数是一个也必然必须是一个 区块(不是proc,去掉&才是proc)
def my_third(&myproc)
puts "I call you! come on"
yield
end
my_third { puts "I'm coming!"}
这里 &myproc 是个区块,而myproc是个proc。对于proc,我们应该可以直接调用proc.call.
所以我们来试试第4个方法:不用yield,而在方法中直接call 这个proc
def my_fourth (&myproc)
puts "I call you! come on"
myproc.call
end
my_fourth { puts "I'm coming!"}
其实 &就是个切换开关,加上这个开关,就可以在proc和block之间切换。proc/lambda 也是一个开关(这两个是内核方法:Kernel#proc :Creates a new procedure object from the given block. Equivalent to Proc.new
.)
def my_fivth (&myproc)
puts "I call you! come on"
#&&myproc.call 这个不行,不能反转两次?
c_proc = proc &myproc
c_proc.call
end
my_fivth { puts "I'm coming!"}
def my_sixth (&myproc)
puts "I call you! come on"
c_proc = lambda &myproc
c_proc.call
end
my_sixth { puts "I'm coming!"}
补充一个小结:
可调用对象,有以下几种形式:块,proc,lambda,方法。不同类的可调用对象有细微区别。
但仍然可以通过以下方法在它们之间转换:包括Proc.new()方法,Methrod#to_proc()方法和&操作符。