2014-03-13 34 views
1
3.times {puts "Hello"} 

输出:作为红宝石方法的参数块是一个谜?

Hello
Hello
Hello

我们把它理解为timesInteger类中的函数,接受block作为参数。

我试图挖掘并发现它并不那么简单。

如果它是times是在一个方法调用的函数,并且括号中的情况下是可选的我试图用它来验证:

3.times({puts "Hello"}) 

扔明显的错误:

SyntaxError: (irb):3: syntax error, unexpected tSTRING_BEG, expecting keyword_do or '{' or '(' 3.times({puts "Hello"}) ^ (irb):3: syntax error, unexpected '}', expecting end-of-input 3.times({puts "Hello"}) ^ from /home/ashish/.rvm/rubies/ruby-2.0.0-p353/bin/irb:12:in `'

进一步调查:

a = 3.times 
puts a.class 

输出Enumerator th意味着3X是一个Enumerator类对象。

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

+3

块“参数”是句法糖;如果你在parens里面做,它会试图解析为一个散列。 –

+0

如果我们在这种情况下尝试“3.times(do puts”hello“end)”,那么为什么它会试图将其解析为散列值? –

+2

'3.times(&proc {puts“Hello”})' –

回答

3

正如Sawa所说,块不是对象,因此不会作为参数传递。在Ruby中块是一件特别的事情。它们有特殊的语法(它只允许我们传递一个方法到一个方法)和一个专门调用它们的特殊关键字。下面是times在Ruby中的范例:

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关键字调用块。

2

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

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

调用它,你需要一个可以转换为一个对象:

+0

它是一个参数,只是一个位置和语法糖,它允许你省略'&'和'proc'。 –

+0

你的言论是矛盾的。 '一个块不是一个参数'并且'取一个块的时间' 考虑一个方法只会把某些事情当作参数。 –

+0

@VictorMoroz根据你的逻辑,女人是一个男人,可以成为一个没有MtoF性别再分配操作的女人。 – sawa

0

是座位置(通常,如果定义的最后一个)与传递值的特殊规则的说法,times可以作为被定义Proc类的一个实例,你应该用&加前缀:

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

调用times

3.times { puts "Hello" } 

只是上述形式的语法糖。

更新:我不得不承认,它不是一个语法糖,块是速度更快,只是增加&block参数times确实慢下来的东西,即使它永远不会被调用。

+3

这不完全是句法糖。 “3.times {puts”Hello“}实际上比”3.times(&Proc.new {puts“Hello”})简单得多。两者都具有相同的最终效果,但是像这样做的包装和解开包装和展开过程涉及更多的工作。此外,说“块是一个位置的争论”有点欺骗性。从语言的角度来看,如果您选择将其包装在Proc中,那才是真实的。 – Chuck

+1

参数必须是一个对象。块不是一个对象。 **证明:**如果一个块是一个对象,它应该是一个'Object'实例,并且应该响应'object_id'方法。但是,“{puts”foo“}。object_id'会引发语法错误。因此,一个块是一个对象的假设是错误的。 QED。 – sawa

+0

@sawa我一直认为它叫做语法糖。我的'times'版本中的'block'同时具有class和'object_id'。简单的例子:'some_method(:a => 1)'。 ':a => 1.object_id'?那些大括号在哪里? –