【问题标题】:Kernel#__method__ doesn't seem to work correctly in dynamically defined methodsKernel#__method__ 在动态定义的方法中似乎无法正常工作
【发布时间】:2011-02-26 21:14:07
【问题描述】:

我一直在尝试在 Ruby 1.9 中动态定义一些实例方法。这是我一直用来尝试的代码:

class Testing
  [:one, :two].each do |name|
    define_method(name) do
      puts __method__
    end
  end
end

这是输出:

ruby-1.9.2-p180 :008 > t = Testing.new
 => #<Testing:0x00000100961878> 
ruby-1.9.2-p180 :009 > t.one
two
 => nil 
ruby-1.9.2-p180 :010 > t.two
two
 => nil 
ruby-1.9.2-p180 :011 > 

我希望结果分别为onetwo。如果我在迭代之外调用每个define_method,它会按预期工作。我在这里不明白什么?

这是我在网上看到的在迭代中调用 define_method 的众多示例之一。 Dynamically defined setter methods using define_method?

缺少什么?

另外:使用__method__ 对我来说并不重要,但这是我可以展示的最佳方式,似乎只有发送到define_method 的最后一个块被用于定义的方法。也许这开始向我解释问题,但我仍然不明白..

【问题讨论】:

  • 我尝试了您的代码,在这里它完美运行,t.one 打印 "one"
  • 这可能是我的 ruby​​ 版本中的错误吗? *编辑:作为记录,这在 Ruby 1.8 中有效
  • 行为在此处确认 (1.9.2),t.one 打印“两个”。闻起来像虫子。

标签: ruby


【解决方案1】:

很好地发现了奇怪的行为。在我测试的所有红宝石中,只有 MRI 1.9.2 可以证明这一点。

Ryan Davis 有 reported the bug on the ruby-core list(参考这个问题)。

【讨论】:

【解决方案2】:

你可以用这样的东西代替define_method:

class Testing
  [:one, :two].each do |name|
    eval <<-EOM 
        def #{name}
            puts __method__
        end
    EOM
  end
end

t = Testing.new
t.one #=> "one"
t.two #=> "two"

【讨论】:

  • 肯定有比这更干净的方法吗?
【解决方案3】:

发生这种情况的原因是,define_method 定义方法的方式与 def 稍有不同。它与创建匿名 procs 和 lambdas 有关。我的建议是简单地使用方法名称,因为您已经拥有它。这应该避免也必须在堆栈跟踪中搜索方法名称,因此它应该执行得更好:

class Testing
  [:one, :two].each do |name|
    define_method name do
      "This method's name is #{name}."
    end
  end
end

Testing.new.one
=> This method's name is one.
Testing.new.two
=> This method's name is two.

为了澄清,请注意以下两个语句返回的内容:

class Testing
  define_method :one do
    __method__
  end
end
=> #<Proc:0x000001009ebfc8@(irb):54 (lambda)>

class Testing
  def one
    __method__
  end
end
=> nil

P.S:使用这两种格式也存在性能差异。您可以使用 Benchmark 验证自己 def 比 define_method 快。

【讨论】:

  • 您的回答是一个很好的“阅读字里行间并弄清楚真正意图是什么”的答案,但看起来Kernel#__method__ 在 MRI 1.9.2 中仍然存在错误。
  • 是的,很可能是这样,但我可以将其视为方法实现方式之间的差异。匿名 proc/lambda 没有方法名称,至少可以解释一些奇怪的行为。
猜你喜欢
  • 1970-01-01
  • 2010-10-18
  • 1970-01-01
  • 2017-09-04
  • 2012-05-06
  • 2013-02-17
  • 2017-10-09
  • 2017-08-03
  • 2014-05-02
相关资源
最近更新 更多