Ruby Blocks, Procs, & Lambdas

682 查看

之前看过codeschool的rubybits的教程,但是看的比较快,掌握的不是太扎实,重新复习下rubybits2的课程,记录一些笔记。

Proc

创建Proc

可以使用 Proc.new 创建一个Proc类的实例,Proc.new返回一个Proc类的对象。比如在codeschool rubybit2 channenge1的main.rb文件里使用Proc.new创建的print_details,这个proc接受一个game实例的参数并打印信息。

library = Library.new(GAMES)
print_details = Proc.new do |game|
  puts "#{game.name} (#{game.system}) - #{game.year}"
end
library.exec_game("Contra", print_details)

library.exec_game("Contra", print_details) 这句代码中proc可以直接作为参数传递。

调用proc

在library.rb的exec_game方法中接受传递的参数并作用于game实例,其中exec_game方法中action是显示传递的proc,每个proc都有一个call方法,调用call方法就会执行这个proc。

代码:

class Library
  attr_accessor :games

  def initialize(games)
    @games = games
  end

  def exec_game(name, action)
    game = games.detect { |game| game.name = name }
        action.call(game)  if game.name == "Contra"
  end
end

使用lambda 重构

上面例子中的Proc.new可以用lambda代替

print_details = lambda {|game| puts "#{game.name} (#{game.system}) - #{game.year}" }

Ruby 新的lanbda语法

ruby1.9后支持的新的语法

print_details = ->(game){ puts "#{game.name} (#{game.system}) - #{game.year}" }

改变
- lambda关键字改为 ->
- 参数在->后面并在括号里,在大括号之外

proc 到 block

使用&proc的形式将proc作为blcok传递
例如

library = Library.new(GAMES)
library.each { |game| puts "#{game.name} (#{game.system}) - #{game.year}" }

可以这样

library = Library.new(GAMES)
print_detail = Proc.new do |game|
    puts "#{game.name} (#{game.system}) - #{game.year}"
end
library.each(&print_detail)

symbol的to_proc

经常看到这样的写法

def names
  games.map(&:name)
end

ruby允许用&开头的符号作为代码块被传递到一个迭代器中,这段代码中将符号(symbol) :name转换成proc传递给map,等价于

 def names
    games.map { |game| game.name }
  end

optional blocks

ruby中block可以是可选的参数,ruby提供了block_given? 方法让我们判断是否有block传递,比如这段代码中的list方法,
list有block传递的时候,调用block,没有的调用game.name

class Library
  attr_accessor :games

  def initialize(games)
    @games = games
  end

 def list
  games.each do |game|
    if block_given?
      puts yield game
    else
      puts game.name
    end
  end
end

proc和lambda的区别

  • lambda会进行参数检查,proc不会
  • proc执行return语句,它会从代码块所在的方法中返回,而lambda仅仅从lambda自身返回,会继续执行方法后面的语句

others:

  1. 理解Ruby的4种闭包:blocks, Procs, lambdas 和 Methods
  2. 理解Ruby中block的本质