Ruby:如何通过对象引用调用函数?

时间:2009-04-30 13:49:22

标签: ruby idioms method-dispatch

考虑这个人为的例子:

# Dispatch on value of fruit_kind:

TYPE_A = :apple
TYPE_B = :banana
TYPE_C = :cherry

eating_method = nil

case fruit_kind
  # Methods to use for different kinds of fruit (assume these are
  #  already defined)
  when TYPE_A then eating_method = bite
  when TYPE_B then eating_method = peel
  when TYPE_C then eating_method = om_nom_nom
end

现在我想用一些参数调用eating_method的目标:

# Doesn't work; this tries to invoke a method called "eating_method",
# not the reference I defined earlier.
eating_method(some_fruit)

在Ruby中执行此操作的正确方法是什么?

4 个答案:

答案 0 :(得分:6)

使用send。发送采用函数名称,因此请使用符号:

case fruit_kind
  # Methods to use for different kinds of fruit (assume these are
  #  already defined)
  when TYPE_A then eating_method = :bite
  when TYPE_B then eating_method = :peel
  when TYPE_C then eating_method = :om_nom_nom
end

send(eating_method, some_fruit)

编辑:

顺便说一句,你是否知道你可以通过做这样的事情来使case变得更漂亮:

eating_method = case fruit_kind
  # Methods to use for different kinds of fruit (assume these are
  #  already defined)
  when TYPE_A then :bite
  when TYPE_B then :peel
  when TYPE_C then :om_nom_nom
  else nil
end

或者,正如Sii所提到的,改为使用哈希:

fruit_methods = {:apple => :bite, :banana => :peel, :cherry => :om_nom_nom}
send(fruit_methods[fruit_kind], some_fruit)    

答案 1 :(得分:1)

在Ruby中,您可以使用类和方法,就像它们是没有太多工作的值一样,因此您可以将实际需要管理的数量减少到单个Class类定义 - >方法并使用通用算法来处理该定义。

假设您的每种类型都实现了您指定的方法,例如: Apple.bite(),Banana.peel()和Cherry.om_nom_nom()都已定义。还假设 fruit fruit_kind 的一个实例。您可以在一个地方管理映射并使用通用方法执行所有类特定方法评估,如下所示:

fruit_table = {Apple => :bite, 
               Banana => :peel,
               Cherry => :om_nom_nom}
eating_method = fruit.method(fruit_table[fruit.type])
eating_method.call

请注意,引用 eating_method 是特定于fruit实例的方法对象的实例。您可以将表定义拉出来作为类变量,但是您希望在每次决定在传递的实例上调用哪个函数的上下文中评估fruit.method。

答案 2 :(得分:0)

措辞让我很困惑。

你可能想要Object#send

答案 3 :(得分:0)

Ruby对象模型允许您使用Object#send方法动态调用方法,该方法将符号作为您要调用的方法。

因此,如果您有一个名为FruitEater的课程,您可以将饮食方法发送为:


f = FruitEater.new

# Dispatch on value of fruit_kind:

TYPE_A = :apple
TYPE_B = :banana
TYPE_C = :cherry

eating_method = nil

case fruit_kind
  # Methods to use for different kinds of fruit (assume these are
  #  already defined)
  when TYPE_A then eating_method = :bite
  when TYPE_B then eating_method = :peel
  when TYPE_C then eating_method = :om_nom_nom
end

f.send(eating_method)