IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Ruby\'s Block and Proc

    Yukang (moorekang@gmail.com)发表于 2012-11-14 00:00:00
    love 0

    Callable objects

    在Ruby当中一切都是对象,但是有一个例外,那就是block。Block和Proc类似,但是还是有稍有差别的,Block更常用一些。最近在看《Metaprogramming Ruby》,在这节中有个例子是这样的。

    require 'highline'
    hl = HighLine.new
    friends = hl.ask("Friends?" , lambda {|s| s.split(',' ) })
    puts "You're friends with: #{friends.inspect}"
    ⇒
    Friends?
    Bill,Mirella,Luca
    You're friends with: ["Bill", "Mirella", "Luca"]
    

    这里看起来hl.ask把Proc当作参数来传递,而不是接受了一个block,接受Block是另外一种使用模式:

    require 'highline'
    hl = HighLine.new
    new_pass = hl.ask("password: ") { |prompt| prompt.echo = false }
    

    在highline代码可以看到相应的处理方式,第一种方式lambda构造成的Proc其实传递给了answer_type,而yield来处理block。

        def initialize( question, answer_type )
          # initialize instance data
          @question    = question
          @answer_type = answer_type
    
          # allow block to override settings
          yield self if block_given?
    

    Proc, Lambda, Block

    有三种方式转化Block为Proc, Proc.new、Lambda、&Operator;。但是在使用过程中Block还是比Proc要常见,在给一个函数传递这种callable objcts的时候,可以隐式或者显示传递,像这样:

    def foo(*args)
     yield(args.join(' '))
    end
    
    foo('Yukang', 'Chen'){|name| puts "Hello #{name}"} # => "Hello Yukang Chen"
    
    def foo(*args, &blk;)
     blk.call(args.join(' '))
    end
    
    foo('Yukang', 'Chen'){|name| puts "Hello #{name}"} # => "Hello Yukang Chen"
    

    隐式传递要比显式传递performance要好一些。这很早就有讨论,具体原因是根据Ruby的实现一个Block在yield的时候并没有转换为Proc或者其他对象,所以少了一些开销。Ruby中的函数块是高阶函数的一种特殊形式的语法,Matz在设计块的时候考虑到: (1)在高阶函数中,这种只有一个函数参数非常常见,在实际使用中几乎没有必要在一个地方使用多个函数参数,(2)外观和形式上更直观,Enumerable利用块写的代码简洁易懂。



沪ICP备19023445号-2号
友情链接