2012-12-27 54 views
3

我对Ruby的Koans工作about_message_passing.rb并得到了工作method_missing的代码如下:红宝石Koans关于通过“发送”消息块和参数

def method_missing(method_name, *args, &block) 
    @messages << method_name 
    @object.__send__(method_name, *args, &block) 
end 

此代码似乎工作,但我不很明白,为什么在参数中需要图示和&是需要的块。

如果我定义了一个方法,我知道*和&分别用于表示一个数组参数和块参数,但是它们与send方法一起用于在对象上调用方法时意味着什么?

回答

9

我会一次拿这一个。完全脱离method_missing,因为这只会让人感到困惑。这实际上完全没有关系。


splat *有2件事。在方法定义的参数中,它将多个参数吸收到一个数组中。当在方法调用中使用时,它将数组划分为单独的参数。使用这两种方法可以将任意数量的参数转发给其他方法。

def foo(*args) 
    bar(*args) 
end 

def bar(a, b, c) 
    puts a 
    puts b 
    puts c 
end 

foo(1,2,3) # prints 1, 2 and then 3 

由于您基本上是转发所有参数,这是相同的模式。


&用于块参数。每个方法调用都可以有其中的一个,它是挂起的块。这是一个特殊的论点,因为它不直接引入论证。通过捕获添加&someblock作为方法定义中的最后一个参数,可以将该块捕获到变量。

然后,您可以使用相同的语法在方法调用中传递一个块。

def foo(&block) 
    bar(&block) 
end 

def bar 
    yield 
end 

foo { puts 'hello' } # prints hello 

这允许您将挂块传递给另一个方法,而不用调用它。它并不总是需要的,因为通常只需使用yield来执行通过的任何块。但是,如果除了执行它之外还想执行某些操作,则需要捕获对块本身的引用。


所以,如果你把这些两件事情,你得到的终极方法转发器。您可以捕获所有任意数量的参数以及任何挂起的块,然后将其发送给其他方法。

# forwards everything to the method `bar` 
def foo(*args, &block) 
    bar(*args, &block) 
end 

最后,send只是一个方法。它需要一个方法的名称,后面跟着任意数量的参数(不是数组),并且可以选择处理挂起的块。

换句话说:

foo.send methodName, *args, &block 
+0

注意,图示并不仅仅适用于方法的参数定义/参数列表。它也适用于块参数定义/参数列表,*和*赋值。 –

0

据我所知,任何时候你直接通过一个块,它的语法是& block_name。

另外,Object#send的方法签名需要无限的参数,而不是数组。所以通过传递splatted的值* args,就像你传递了逗号分隔的参数一样。

1

方法定义中的图示意味着“取所有不匹配的参数并将它们放入一个数组中”(在ruby 1.8中,这总是最后一个参数,但在1.9中可以出现splat)。

在一个方法调用使用它是反向:它意味着借此阵列和使用它的内容作为参数

foo(a,b) #call foo with 2 arguments: a and b 
foo([a,b]) #call foo with a single array argument 
foo(*[a,b]) # call foo with 2 arguments: a and b 

&是相似的:在一个方法定义它捕获块并把它变成一个proc,但在一个方法调用它将一个proc(或proc像对象 - 任何响应to_proc将做)到该方法的块

你需要这两个为method_missing,因为(一般)你想通过沿着原始方法调用的所有参数和块。