Ruby Koans 关于消息传递"send"块和参数



我正在Ruby Koans about_message_passing上工作。让代码为method_missing工作,如下所示:

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

这段代码似乎可以工作,但是我不太明白为什么在*args和&

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

我一次拿一个。把method_missing完全拿出来,因为它只会让事情变得混乱。它实际上与那个完全无关。


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

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

因为你基本上转发了所有的参数,所以这是相同的模式。


&用于block参数。每个方法调用只能有一个,它是挂起的块。这是一个特殊的参数,因为它不直接进入参数。您可以通过捕获add &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

方法定义中的splat表示"取所有不匹配的参数并将它们放入数组中"(在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

,是类似的:在方法定义中,它捕获块并将其转换为过程,但在方法调用中,它将过程(或类似过程的对象-任何响应to_proc的对象都可以)转换为该方法的块

对于method_missing,您需要这两种方法,因为(通常)您希望传递原始方法调用中的所有参数和块。

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

同样,object# send的方法签名接受无穷参数,而不是一个数组。因此,通过传递散列值*args,就相当于传递了以逗号分隔的args。

最新更新