Ruby Block Part Two
本部分内容是基于Ruby 1. 8. 7, 以后的系列都是1.8.7下测试。


例子1 :
def return_using_procnew
  a_proc = Proc.new { return "Hi" }
  a_proc.call
  "Last line in the method"
end

=>  “ Hi”

def return_using_lambda
  a_proc = lambda { return "Hi" }
  a_proc.call
  "Last line in the method"
end
=> "Last line in the method"

以上例子可以看出lambda和Proc.new的区别, 用lambda的时候return会被劫持, 而Proc.new则不会。

例子2:
def foo(proc_one,proc_two)
  proc_two.call
  proc_one.call
end

foo(lambda {p "Proc 1"}, lambda {p "Proc 2"})     =>   "Proc 2"  "Proc 1"

def foo(proc_one,proc_two)
  proc_one.call
  proc_two.call
end

foo(lambda {p "Proc 1"}, lambda {p "Proc 2"})     =>   "Proc 1"    "Proc 2"


例子3:

def foo(&my_block)
   my_block.call
end

foo { puts "Hi" }
=>        Hi

foo (lambda{ puts "Hi" })
=> ArgumentError: wrong number of arguments (1 for 0)

def foo(a,&my_block)
  a.call
end

foo (lambda{ puts "Hi" })
 =>   Hi

def foo(&my_block)
  my_block.call
end

foo { puts "Hi" } 
=>  Hi

例子4:

1.times do
  x = 5
  closure = Proc.new {puts "In clsure value of x is #{x}
end

closure.call
=>     In clsure value of x is 5

x = 1

puts x
=>     1

closure.call
 =>     In clsure value of x is 5


由此看出,闭包引用的变量是call这个proc对象时产生的变量,在外部修改其值是没用的。

例子5:
class GreetingGenerator
  def initialize(greeting)
    @my_block = lambda {|name| puts "#{greeting}, #{name}"}
  end
  def greet(name)
    @my_block.call name
  end
end
frenchGreeting = GreetingGenerator.new “Bonjour”
englishGreeting = GreetingGenerator.new “Hello”
frenchGreeting.greet “TinTin”
    =>     Bonjour, TinTin
englishGreeting.greet “Bunny”
    =>     Hello, Bunny

这你能看出来什么 ?
例子6:
def repeat(n)
  n.times {yield} if block_given?
end  
repeat(2) {puts "Hi"}

def repeat2(n, &block)
  n.times {block.call} if block
end
repeat2(2) {puts "Hi2"}

def repeat3(n,&block)
  n.times {yield} if block
end
repeat3(2){ puts "Hi3" }

这三种写法的目的是一样的。
例子7:
  print  "(t)imes or (p)lus"

  times = gets

  print "number:"
  number =  Integer(gets)
  if times =~ /^t/
    calc = lambda {|n| n*number }
  else
    calc = lambda {|n| n + number}
  end

  p((1..10).collect(&calc).join(", "))

这个例子也是闭包的概念。
例子8:
words = %w(Daffy, Bugs, Alvin)
upcase_words = words.map( &:upcase )

p upcase_words

例子的map(&:upcase)相当于map{ |x| x.upcase }
这个是如何实现的? 其实Symbol类内部实现了一个to_proc方法:
class Symbol
  def to_proc
    lambda { |x,*args| x.send(self, *args) }
  end
end

map方法只接受代码块,通过使用&可传递proc,来代替显示的使用代码块。而这个时候&被应用于不是proc的对象,而传进来的本身是个符号对象(:&upcase),所以解释器自然而然的就会调用符号类的to_proc方法来得到一个proc。to_proc方法里的self引用的是对其调用了to_proc的符号。