【问题标题】:Ruby: How do I invoke a function via an object reference?Ruby:如何通过对象引用调用函数?
【发布时间】:2009-04-30 13:49:21
【问题描述】:

考虑这个人为的例子:

# 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 中执行此操作的正确方法是什么?

【问题讨论】:

    标签: ruby idioms method-dispatch


    【解决方案1】:

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

    编辑:

    顺便说一句,您知道吗,您可以通过执行以下操作使 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)    
    

    【讨论】:

      【解决方案2】:

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

      假设您的每个类型都实现了您指定的方法,例如Apple.bite()、Banana.peel() 和 Cherry.om_nom_nom() 都已定义。还假设 fruitfruit_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.method。

      【讨论】:

        【解决方案3】:

        措辞让我很困惑。

        你可能想要Object#send

        【讨论】:

        • 也就是说,我有点不喜欢这个设计。在水果上做一个#eat方法更有意义,或者有case/when直接调用负责的方法,或者至少为fruit_kind =>方法符号使用哈希。
        • 我完全同意这将是一种代码味道。在名称上调度通常是一个糟糕的主意。我更感兴趣的是如何通过引用调用函数。感谢您的帮助!
        【解决方案4】:

        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)
        

        【讨论】:

          猜你喜欢
          • 2012-02-03
          • 1970-01-01
          • 2013-07-19
          • 2014-11-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-11
          • 1970-01-01
          相关资源
          最近更新 更多