Ruby中的动态方法调用是什么?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (21)

据我所知,在Ruby中动态调用方法有三种方法:

方法1:

s = SomeObject.new
method = s.method(:dynamic_method)
method.call

方法2:

s = SomeObject.new
s.send(:dynamic_method)

方法3:

s = SomeObject.new
eval "s.dynamic_method"

通过对它们进行基准测试,我确定了方法1是迄今为止最快的,方法2是慢的,方法3是最慢的。

我还发现.call.send都允许调用私有方法,而eval不会。

所以我的问题是:有没有理由用.sendeval?为什么不总是用最快的方法?这些调用动态方法的方法还有哪些不同之处?

提问于
用户回答回答于

有什么理由用send

call需要一个方法对象,send不会:

class Foo
  def method_missing(name)
    "#{name} called"
  end
end

Foo.new.send(:bar)         #=> "bar called"
Foo.new.method(:bar).call  #=> undefined method `bar' for class `Foo' (NameError)

有什么理由用eval

eval计算任意表达式,这不仅仅是为了调用一个方法。


关于基准,send似乎比method+call更精确:

require 'benchmark'

class Foo
  def bar; end
end

Benchmark.bm(4) do |b|
  b.report("send") { 1_000_000.times { Foo.new.send(:bar) } }
  b.report("call") { 1_000_000.times { Foo.new.method(:bar).call } }
end

结果:

           user     system      total        real
send   0.210000   0.000000   0.210000 (  0.215181)
call   0.740000   0.000000   0.740000 (  0.739262)
用户回答回答于

这样想一想:

方法1(method.call):单次运行时

如果直接在程序中运行一次Ruby,则可以控制整个系统,并且可以通过“method.call”方法保存“指向你的方法的指针”。所做的只是持续处理“实时代码”,可以随时运行。这基本上与直接从对象内部调用方法一样快(但它不如使用object.send快 - 请参阅其他答案中的基准)。

方法2(object.send):将方法的名称保存到数据库

但是如果你想将你想调用的方法的名字存储在数据库中,并且在未来的应用程序中想要通过在数据库中查找来调用该方法名称呢?然后你会使用第二种方法,这会导致ruby使用第二个“s.send(:dynamic_method)”方法调用任意方法名称。

方法3(eval):自修改方法代码

如果你想以一种将该方法作为全新代码运行的方式来编写/修改/保存代码到数据库呢?你可能会定期修改写入数据库的代码,并希望每次都以新代码运行。在这种情况下,会希望使用第三种方法,它允许将方法代码编写为字符串,稍后将其加载回来,并将其全部运行。

对于它的价值,通常认为在Ruby世界中使用Eval(方法3)是一种糟糕的形式,除非在非常非常深奥和罕见的情况下。所以你应该坚持使用方法1和2来解决几乎所有遇到的问题。

扫码关注云+社区