调用方法作为块

时间:2013-07-13 17:17:03

标签: ruby refactoring

红宝石世界的初学者,我想做点什么:

[1,2.0,"a",2].select(&:is_a?(Integer))

但是这样肯定不起作用......

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

您无法满足要求,因为当您使用&语法时,必须使用不带参数的方法。

但是,如果你出于某些原因想要做类似的事情,你需要制作一个不带参数的方法:

class Object
  def is_an_integer?
   is_a? Integer
  end
end

然后你可以这样做:

[1,2.0,"a",2].select(&:is_an_integer)

答案 1 :(得分:1)

&:method_name&:method.to_proc的语法糖。枚举器如select和诸如此类的接受块并将枚举器的每个元素都放到传递的块中。那就是:

[1,2,3].select &:even?

相当于:

p = :even.to_proc
[1,2,3].select {|val| p.yield(val) }

由于只有枚举器产生的参数会产生于proc,因此您必须将它们包含在源列表中。也就是说,我们可以期待:

[[1, Integer]].select &:is_a?

导致:

select {|*args|, p.yield(*args) }

但是,请记住p不是绑定到任何特定类的方法!它将尝试在传递的参数上调用给定的方法。因此,它会尝试不带参数调用Array#is_a?,而不是将参数展开并调用Integer#is_a?(Integer)

因此,为了实现这一点,我们必须以某种方式创建一个绑定传递的参数的proc,然后使用传递的args在生成的接收器上调用给定的方法。我们可以通过向Symbol类添加一个方法来实现:

  class Symbol
    def with_args(*args)
      proc {|receiver| receiver.send(self, *args) }
    end
  end

  [1, "a"].select &:is_a?.with_args(Integer)

虽然它可能不是很干净,但确实有效。

相关问题