据我所知,在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)

Ruby相关问答推荐

类似于模块的 attr_accessor 和 attr_reader 的东西?

如何根据数组键对散列键进行排序?

Ruby 避免类方法并保持其类型系统简单优雅的秘诀

当Ruby `Complex` 类除了`==` 之外没有任何关系运算符时,它的祖先怎么能有`Comparable`?

如何在 OpenURI 中指定http 请求标头

bundler 可以告诉我 Gemfile 中的哪些 gem 有更新的版本

如何记录在 Ruby 程序中调用的每个方法?

为什么 Range 在下降时不起作用?

如何使用 capybara + cucumber 断言 ruby​​ 中的 html 表行数

如何从 Gemfile 安装 gem?

有没有办法在 RSpec 中取消存根?

ActionController::UnknownFormat

在 Ruby 中,有没有办法使用 hash.each_with_index do |[k,v], i| 之类的东西?

在 ruby​​ 的超类中调用另一个方法

错误:Windows 的 SASS 安装

如何在课堂上使用 Enumerable mixin?

如何计算Ruby日期的星期几?

Ruby中的urldecode?

Ruby - 无法修改冻结的字符串 (TypeError)

查找与给定条件匹配的元素的索引