Ruby Koans关于传递"发送"块和参数的消息

Zen*_*nce 3 ruby methods block send splat

我正在研究Ruby Koans的about_message_passing.rb,并使代码适用于method_missing,如下所示:

def method_missing(method_name, *args, &block)
  @messages << method_name
  @object.__send__(method_name, *args, &block)
end
Run Code Online (Sandbox Code Playgroud)

这段代码似乎有效,但我不太明白为什么需要*args中的splat和块中需要&.

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

Ale*_*yne 9

我会一次拿这些.取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
Run Code Online (Sandbox Code Playgroud)

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


&是该块参数.每个方法调用中可以只有一个,它是挂起的块.这是一个特殊的论点,因为它不直接参与论证.您可以通过将add &someblock作为方法定义中的最后一个参数捕获来将块捕获到变量中.

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

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

def bar
  yield
end

foo { puts 'hello' } # prints hello
Run Code Online (Sandbox Code Playgroud)

这允许您将挂起块传递给另一个方法,而无需调用它.它并不总是必需的,因为你通常只是yield用来执行传递的任何块.但是如果除了执行它之外你还想做一些事情,你需要捕获对块本身的引用.


因此,如果您将这两件事结合起来,您将获得最终的方法转发器.您捕获所有任意数量的参数,以及任何挂起的块,并将它们发送到另一个方法.

# forwards everything to the method `bar`
def foo(*args, &block)
  bar(*args, &block)
end
Run Code Online (Sandbox Code Playgroud)

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

换一种说法:

foo.send methodName, *args, &block
Run Code Online (Sandbox Code Playgroud)