块作为ruby中方法的参数是一个谜?

时间:2014-03-13 16:58:27

标签: ruby methods arguments block

3.times {puts "Hello"}

输出:

  

您好
     你好
     你好

我们理解为timesInteger类中的一个函数,它以block为参数。

我试图深入挖掘并发现它并非那么简单。

如果times是一个函数并且方法调用中的括号是可选的,我尝试使用以下方法验证它:

3.times({puts "Hello"})
它显然犯了一个错误:

  

SyntaxError:(irb):3:语法错误,意外tSTRING_BEG,期待keyword_do或'{'或'(''   3次({puts“你好”})                  ^   (irb):3:语法错误,意外'}',期待输入结束   3次({puts“你好”})                         ^       来自/home/ashish/.rvm/rubies/ruby-2.0.0-p353/bin/irb:12:in`'

进一步调查:

a = 3.times
puts a.class

输出Enumerator,表示3次是Enumerator类对象。

有人可以用这个背后的确切概念解释整个事情吗?

3 个答案:

答案 0 :(得分:3)

Sawa说,块不是对象,因此不作为参数传递。块在Ruby中是一个特殊的东西。它们具有特殊语法(只允许我们将一个块传递给方法)和一个专用于调用它们的特殊关键字。这是Ruby中times的示例实现:

def times
  if block_given?
    i = 0
    while i < self
      yield i
      i += 1
    end
    # times returns the number that was executing times,
    # so we need to return self here
    self
  else
    enum_for :times
    # ^^ This is where the Enumerator comes from if
    #    you don't pass a block.
  end
end

block_given?方法测试是否存在与当前方法关联的块,yield关键字调用该块。

答案 1 :(得分:2)

块不是参数,它甚至不是对象。将它括在括号中是没有意义的,因为它不是一个对象。

答案 2 :(得分:0)

Block是一个位置(总是最后一个,如果已定义)参数,带有一个传递值的特殊规则,times可以定义为:

def times(&block)
  block.call(...)
end

要调用它,你需要一个可以转换为Proc类实例的对象,你应该在&之前添加它:

3.times(&Proc.new { puts "Hello" })

调用times之类的

3.times { puts "Hello" }

只是上述形式的语法糖。

更新:我不得不承认它不是语法糖,块速度更快,只需向&block添加times参数即使从未调用它也会减慢速度