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

发布于 2024-07-18 12:21:32 字数 630 浏览 10 评论 0原文

考虑这个人为的示例:

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

Consider this contrived example:

# 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

Now I'd like to invoke the target of eating_method with some arguments:

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

What's the right way to do this in Ruby?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

北恋 2024-07-25 12:21:32

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

Use send. Send takes the function name, so use symbols:

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)

EDIT:

By the way, did you know you can make that case a little prettier by doing something like this:

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

Or, as Sii mentions, use a hash instead:

fruit_methods = {:apple => :bite, :banana => :peel, :cherry => :om_nom_nom}
send(fruit_methods[fruit_kind], some_fruit)    
迷爱 2024-07-25 12:21:32

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

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

In Ruby you can use classes and methods as if they are values without too much work, thus you can reduce the amount you actually have to manage in your example to a single definition of Class -> Method and use a generalized algorithm to work with that definition.

Suppose each of your types implement the methods you specify, e.g. Apple.bite(), Banana.peel(), and Cherry.om_nom_nom() are all defined. Also suppose that fruit is an instance of fruit_kind You can manage the mapping in one place and use a generalized method to do all of the Class specific method evaluation like so:

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

Note that the reference eating_method is an instance of a method object specific to the instance of fruit. You could pull the table definition out to be a class variable, but you would want to evaluate fruit.method in the context of each time that you are deciding which function to call on an instance you are passed.

野の 2024-07-25 12:21:32

措辞让我非常困惑。

不过,您可能需要 Object#send

The wording confuses me greatly.

You probably want Object#send though.

假装不在乎 2024-07-25 12:21:32

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

因此,如果您有一个名为 FruitEater 的类,您可以将 eat 方法发送为:


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)

The Ruby object model lets you call methods dynamically using the Object#send method which takes a symbol as the method you want to call.

So if you were to have a class called FruitEater you could send the eating method as:


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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文