在Ruby中使用具有方法名称的字符串调用方法


157

我该怎么做什么,他们都在谈论这里,但在红宝石?

您将如何对对象执行功能?以及如何执行全局功能(请参阅提到的帖子上的jetxee 回答)?

示例代码:

event_name = "load"

def load()
  puts "load() function was executed."
end

def row_changed()
  puts "row_changed() function was executed."
end 

#something here to see that event_name = "load" and run load()

更新: 如何获得全局方法?还是我的全局功能?

我尝试了这条额外的线

puts methods

并在未列出的位置加载和row_change。

Answers:


232

直接在对象上调用函数

a = [2, 2, 3]
a.send("length")
# or
a.public_send("length")

如预期返回3

或用于模块功能

FileUtils.send('pwd')
# or
FileUtils.public_send(:pwd)

和本地定义的方法

def load()
    puts "load() function was executed."
end

send('load')
# or
public_send('load')

说明文件:


3
+1可行。这可能是一个愚蠢的跟进工作...但是为什么我无法在Ruby源代码中找到发送的单词-C:\ ruby​​ \ lib \ ruby​​ \ 1.8 \ fileutils.rb?以为我会在那里找到发送功能。
BuddyJoe

1
我很好奇它在幕后所做的事情。
BuddyJoe

它是在对象上定义的-ruby-doc.org/core/classes/Object.html#M000332我选择了一个随机函数作为利息值。
Colin Gravill 09年

1
有趣的是,在我两次阅读您的答案并完全理解它之前,我运行了FileUtils.send(“ load”)并运行了我的函数。因此,如果我通过在“全局”中创建函数来正确理解这一点,是否会将方法添加到根对象上?或不?
BuddyJoe

12
很好,您可以从源代码中查找内容!:)
Colin Gravill 09年

34

三种方式:send/ call/ eval-及其基准

典型调用(供参考):

s= "hi man"
s.length #=> 6

使用 send

s.send(:length) #=> 6

使用 call

method_object = s.method(:length) 
p method_object.call #=> 6

使用 eval

eval "s.length" #=> 6

 

基准测试

require "benchmark" 
test = "hi man" 
m = test.method(:length) 
n = 100000 
Benchmark.bmbm {|x| 
  x.report("call") { n.times { m.call } } 
  x.report("send") { n.times { test.send(:length) } } 
  x.report("eval") { n.times { eval "test.length" } } 
} 

...如您所见,实例化方法对象是调用方法中最快的动态方法,还要注意使用eval有多慢。

#######################################
#####   The results
#######################################
#Rehearsal ----------------------------------------
#call   0.050000   0.020000   0.070000 (  0.077915)
#send   0.080000   0.000000   0.080000 (  0.086071)
#eval   0.360000   0.040000   0.400000 (  0.405647)
#------------------------------- total: 0.550000sec

#          user     system      total        real
#call   0.050000   0.020000   0.070000 (  0.072041)
#send   0.070000   0.000000   0.070000 (  0.077674)
#eval   0.370000   0.020000   0.390000 (  0.399442)

值得一提的是这篇博客文章,其中详细介绍了这三种方法,并显示了如何检查这些方法是否存在。


我只是找到了这个,然后发现了一些未涵盖的内容。我想怎么办Class.send("classVariable") = 5?这引发了错误。有什么办法解决吗?同样的事情是真实的使用Class.method("classVariable").call() = 5
thesecretmaster

如果您想通过发送调用发送一些参数,请使用此类ClassName.send(“ method_name”,arg1,arg2)
Aleem

您的基准测试是否不应该call包括实例化方法对象(m.test.method(:length))以准确表示其真实时间?使用时,call可能每次都会实例化方法对象。
Joshua Pinter

博客帖子链接已死,顺便说一句。
Joshua Pinter

33

用这个:

> a = "my_string"
> meth = a.method("size")
> meth.call() # call the size method
=> 9

简单吧?

至于global,我认为Ruby的方式是使用methods方法搜索它。


meth = a.method?这不是已经调用了函数吗?如果该方法返回某些内容怎么办?
user1735921

仅供参考,该方法不存在:"my_string".method('blah') #=> NameError: undefined method 类的“亵渎”String'
Joshua Pinter

3

就个人而言,我将设置一个散列以函数引用,然后将字符串用作散列的索引。然后,您可以使用其参数调用函数引用。这样的好处是不允许错误的字符串调用您不想调用的东西。另一种方法是基本上eval将字符串。不要这样做。

PS不会偷懒,实际上可以输入整个问题,而不是链接到其他内容。


抱歉。我将复制一些措辞并将其翻译为特定于Ruby的语言。+1
BuddyJoe
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.