【问题标题】:Calling a Method From a String With the Method's Name in Ruby在 Ruby 中使用方法名称从字符串调用方法
【发布时间】:2010-11-27 07:20:08
【问题描述】:

我怎样才能做到他们所说的here,但在 Ruby 中?

你会如何对一个对象执行这个函数?以及您将如何执行全局功能(请参阅提到的帖子中的 jetxee 的answer)?

示例代码:

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

并在未列出的地方加载和行更改。

【问题讨论】:

    标签: ruby metaprogramming


    【解决方案1】:

    直接在对象上调用函数

    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')
    

    文档:

    【讨论】:

    • +1 这行得通。这可能是一个愚蠢的后续行动......但为什么我在 - C:\ruby\lib\ruby\1.8\fileutils.rb 的 Ruby 源代码中找不到单词发送?以为我会在那里找到发送功能。
    • 我很好奇它在后台做了什么。
    • 它在对象上定义 - ruby-doc.org/core/classes/Object.html#M000332 我选择了一个随机函数作为兴趣值。
    • 有趣,因为在我两次阅读您的答案并完全理解之前,我运行了 FileUtils.send("load") 并运行了我的函数。所以如果我通过在“全局”中创建函数来正确理解这一点,我是否将这些方法添加到根对象中?还是不行?
    • 感谢您在源代码中查找内容! :)
    【解决方案2】:

    三种方式: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)
    

    感谢blog post,它详细说明了这三种方法,并展示了如何检查这些方法是否存在。

    【讨论】:

    • 我刚刚发现这个,我注意到了一些没有被覆盖的东西。如果我想做Class.send("classVariable") = 5,我会怎么做?这会引发错误。有什么办法吗?使用Class.method("classVariable").call() = 5 也是如此
    • 如果你想通过发送调用发送一些参数,请使用类似 ClassName.send("method_name", arg1, arg2)
    • 您的call 基准不应该包括实例化方法对象(m.test.method(:length)) 以准确表示它的真实时间吗?使用call 时,您可能每次都会实例化方法对象。
    • 博文链接已失效,顺便说一句。
    【解决方案3】:

    使用这个:

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

    简单吧?

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

    【讨论】:

    • meth = a.method?这不是已经调用函数了吗?如果方法返回一些东西怎么办?
    • 当方法不存在时仅供参考:"my_string".method('blah') #=> NameError: undefined method blah' 用于类 String'
    【解决方案4】:

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

    PS 不要偷懒,要真正输入你的整个问题,而不是链接到某个东西。

    【讨论】:

    • 对不起。我将复制一些措辞并翻译成特定于 Ruby 的内容。 +1
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-03
    • 1970-01-01
    • 2013-07-18
    • 1970-01-01
    • 1970-01-01
    • 2012-07-09
    相关资源
    最近更新 更多