您的位置:首页 > 编程语言 > Ruby

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()方法和&操作符。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐