Proc、Block的区别与使用

  代码块,我的理解就是匿名方法,有点像Java中的匿名类一样,似乎用更贴切的说法叫闭包,一个我至今未接触过的东西。学习到代码块和代码块对象(Proc)的时候,看着很晕,一个代码块对象可以用lambda和->同时定义,与对代码块的错误理解纠结在一起,晕了一晚上。今天早上又找了些资料看看,最终才弄懂。写这篇文章的时候,使用的Ruby是1.9.2

 

  Block和Proc的区别就是Proc是Block Object,需要用call方法调用,而Block则不用。

 

1.  代码块的定义分为两种方式调用,一种是do end定义,适用于多行代码,一种是{}定义,适用于一行,两者没有优劣,只有习惯的不同,遵从这种文化吧。

    下面这个就是最简单的代码块示例:

 

5.times do |i|
  puts "No.#{i+1}"
end

 

   但是,如果你想在一个方法调用一个外部的代码块,如何做到呢?这个magic可以通过yield关键字来做到

 

 

def bye(name)
  puts "bye,#{name}"
  if block_given?
    yield
  end
end

bye("Steve Jobs"){puts "missing you "}

    代码块可以作为一个隐含参数,并且是最后一个,而且只能使用一个,来传递给别的方法,前面正常的参数要用括号起。像这个例子,我传递了一个打印“missing you”的代码块给方法bye,通过block_given?来判断是否传递了一个代码块过来,传过来的话,则用yield执行,如果不判断,而直接使用yield的时候,没传代码块是要报错的。其输出结果为:

bye,Steve Jobs
missing you 

 

2.Proc的使用

   Proc就是代码块对象,既然是对象,一旦定义,就可以多次使用了,Proc当然可以用new来创建,这个似乎并不常用,常用的倒是用lambda方法和符号->来定义

2.1 lambda方式

    在方法名lambda后面加上代码块即可,示例如下:

 

proc=lambda {|name| puts "hello,#{name}"}
proc.call 'theoffspring'
proc.call 'Mike'

  输出结果是:

hello,theoffspring
hello,Mike

   而且,作为对象,它可以作用参数传递给方法调用,个数不限,位置不限,这点克服了代码块来作为参数传递的局限性,如:

 

def test_proc_multi_params(name, proc, proc2)
  puts "#{name} is coming ,and he wants to..."
  proc.call
  proc2.call
end

test_proc_multi_params("the offspring", lambda { puts "eat potato" }, lambda { puts "and water melon" })

  输出结果:

the offspring is coming ,and he wants to...
eat potato
and water melon 

   不过 ,代码块可以通过在参数名前加个&来转换成代码块对象,但仍然只能有一个,且在方法参数列表的最后,如:

 

def test_converted_block(name,&action)
  puts "#{name} is "
  action.call
end

test_converted_block("the offspring") {puts "eating lunch"}

 

  输出:

the offspring is
eating lunch 

注意调用   test_converted_block的参数写法,挺特殊的,不得不承认

 

2.2 ->方式

   你只要把lambda出现的地方换成->就行了,哦,对了,这种方式在定义Proc参数的时候,要写到括号的外面,多个的话,以逗号分隔。

    如:

 

proc=-> name { puts "hello,#{name}" }
proc.call 'theoffspring'
proc.call 'Mike'

你可能感兴趣的:(block)