ruby中的&操作符,以及各种闭包、proc的调用研究
2012-03-08 01:11
453 查看
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()方法和&操作符。
相关文章推荐
- Ruby中的各种方法定义和调用(函数式方法|实例方法|类方法)
- deepin系统下安装rubymine以及各种ruby编辑环境体验
- Liferay研究之十五:Liferay如何对外提供Service,以及如何调用
- 玩转Ruby系列:玩转闭包(Block,Proc,lambda)
- Android各种屏幕的分布率以及自适应各种屏幕的开发研究
- Activity调用方式的研究以及跨app调用分析与举例2
- Ruby之旅(二) Ruby的基本语法以及对象的使用,方法的定义及调用,属性的定义及使用
- Ruby中使用Block、Proc、lambda实现闭包
- Activity调用方式的研究以及跨app调用分析与举例1
- oracle的存储过程写法以及调用,各种游标的介绍(静态,动态,sys游标的区别)
- 黑马程序员---注解与反射的调用以及添加各种属性
- C#调用C++编写的DLL函数, 以及各种类型的参数传递 不指定
- C#调用C++编写的DLL函数, 以及各种类型的参数传递
- Android各种屏幕的分布率以及自适应各种屏幕的开发研究
- C#调用C++编写的DLL函数, 以及各种类型的参数传递
- 函数调用时的栈帧结构以及临时变量的深入研究
- Java连接各种数据库以及调用存储过程
- 动态函数调用实现下列操作,输入2个数以及操作符计算结果。 @ 求最大公约数 $求最小公倍数 - 求差 + 求和 等等
- C#调用C++编写的DLL函数, 以及各种类型的参数传递
- Lua Faq翻译之为什么lua中没有类似于+=的操作符以及用Lua实现C++中的<<操作符