rails on ruby,ruby on rails 之代码块(二)

可调用对象
从底层看,使用代码块分为两步。第一步,将代码打包备用;第二步,调用代码块(比如通过yield语句)执行代码。这种“打包代码,以后调用“的机制并不是代码块的专利。在Ruby中,至少还有其他三种方法可以用来打包代码:

  • 使用proc,proc是由块转换来的对象
  • 使用lambda,它是proc的变种

Proc对象
尽管Ruby中绝大多数的东西都是对象,但是代码块却不是。为什么要重点说明这个点呢?因为假如我们想存储一个块供以后执行,我们就需要一个对象。
为了解决这个问题,Ruby的标准库中提供了一个名为Proc的类。Proc就是由块转换过来的对象。下面我们来看看把代码块转换为Proc的三种种方式:
1. 可以使用Proc.new方法来创建一个Proc, 这个Proc#call的方法,是一种被称为延迟执行的技巧。

inc = Proc.new {|x| x+1}
inc.call(2)   # => 3
  1. Ruby还有两个内核方法将块转换为Proc:,首先介绍的是lambda方法:
dec = lambda {|x| x-1 }
dec.class    # => Proc
dec.call(2)  # => 1  
  1. 我们还可以使用一种叫带刺的(stabby)*lambda操作符创建lambda:
p = ->(x) { x + 1 }
其实它等价于:
p = lambda {|x| x+1 }

&操作符
在绝大多数情况下,在方法中可以通过yield语句直接运行一个代码块,但是在下面两种情况下,yeild就显得力不从心了:
1. 想把代码块传递给另外一个方法(甚至代码块)
2. 想把代码块转换成Proc
在这种情况下,我们需要给代码块去一个名字,要将代码块附加到一个绑定上。我们可以给这个方法添加一个特殊的参数,这个参数必须是列表中的最后一个,而且是以&符号开头。下面我们先来举一个&符号的例子:

def math(a, b)
   yield(a, b)
end

def do_math(a, b &operation)
    math(a, b, &operation)
end
do_math(2, 3) {|x, y| x*y}  #=>6    

但是这里有一个漏洞,那就是如果调用do_math方法时没有附加代码块,那么&operation参数将被赋值成nil,这样math方法中的yield操作将会失败。

下面我们再看一种将代码块转化为Proc的方式。我们再来重新回顾一下&操作符的含义:这是以一个Proc对象,但是我想把它当作代码块来使用。Proc是一种用于存储代码块用于以后执行的对象。所以在代码中,只要我们将&去掉,就能再次得到一个Proc对象:

def my_method(&the_proc)
    the_proc
end

p = my_method {|name| "Hello, #{name}!"}
p.class        # => Proc
p.call("Bill") # => "Hello, Bill"   

当我们重新想把Proc对象转换为代码块,只要我们重新加上&操作符就好:

block/proc_to_block.rb
def my_method(greeting)
   "#{greeting}, #{yield}"
end
my_proc = proc("Bill")
my_method("Hello", &my_proc)    

猜你喜欢

转载自blog.csdn.net/zyhmz/article/details/80646464