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

Ruby:如何通过对象引用调用函数?,ruby,idioms,method-dispatch,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_m

考虑这个人为的例子:

# 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\u方法的目标:

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

用Ruby做这件事的正确方法是什么?

使用
send
。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)

编辑: 顺便问一下,你知道吗,你可以通过这样做来使
案例变得更漂亮一些:

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)    

使用
发送
。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)

编辑: 顺便问一下,你知道吗,你可以通过这样做来使
案例变得更漂亮一些:

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)    

这措辞使我大为困惑


不过你可能想要。

这句话让我很困惑


不过,您可能需要。

在Ruby中,您可以像使用值一样使用类和方法,而无需做太多工作,因此您可以将示例中实际需要管理的数量减少为类->方法的单个定义,并使用通用算法来处理该定义

假设您的每个类型都实现了您指定的方法,例如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

请注意,引用方法是特定于水果实例的方法对象的实例。您可以将表定义提取为类变量,但您希望在每次决定对传递的实例调用哪个函数时,在上下文中计算fruit.method。

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

假设您的每个类型都实现了您指定的方法,例如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

请注意,引用方法是特定于水果实例的方法对象的实例。可以将表定义提取为类变量,但是,您可能希望在每次决定对传递的实例调用哪个函数时都对fruit.method进行评估。

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

因此,如果您有一个名为“水果食者”的类,那么您可以通过以下方式发送食用方法:


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)

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

因此,如果您有一个名为“水果食者”的类,那么您可以通过以下方式发送食用方法:


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)

也就是说,我有点不喜欢这个设计。在水果上创建一个#eat方法更有意义,或者让case/when直接调用负责的方法,或者至少对水果#kind=>方法符号使用哈希。我完全同意这将是一种代码味道。按姓名发送通常是个糟糕的主意。我更感兴趣的是如何通过引用调用函数。谢谢你的帮助!也就是说,我有点不喜欢这个设计。在水果上创建一个#eat方法更有意义,或者让case/when直接调用负责的方法,或者至少对水果#kind=>方法符号使用哈希。我完全同意这将是一种代码味道。按姓名发送通常是个糟糕的主意。我更感兴趣的是如何通过引用调用函数。谢谢你的帮助!