Ruby 改进陷阱

Ruby refinements gotchas

在第 2 章的 Metaprogramming Ruby 2 中的“Refinements”部分,我找到了以下 Ruby 代码:

class MyClass 
  def my_method
    "original my_method()"
  end

  def another_method 
    my_method
  end

end

module MyClassRefinement 
  refine MyClass do
    def my_method
      "refined my_method()"
    end 
  end
end

using MyClassRefinement
MyClass.new.my_method # => "refined my_method()"
MyClass.new.another_method # => "original my_method()" - How is this possible?

据作者说:

However, the call to another_method could catch you off guard: even if you call another_method after using, the call to my_method itself happens before using — so it calls the original, unrefined version of the method.

这完全把我绊倒了。

为什么 MyClass.new.another_method 打印 "original my_method()" 因为它在 using MyClassRefinement 之后使用,作者在这里想说什么?

谁能提供更多intuitive/better解释?

谢谢。

我能找到的最好的解释来自 the docs:

Refinements are lexical in scope. Refinements are only active within a scope after the call to using. Any code before the using statement will not have the refinement activated.

这意味着您的优化方法必须在调用 using 之后的某处调用。调用方法的实际位置才是最重要的,而不是调用方法的方式或调用方法的位置。


事情是这样的。

  1. usingusing MyClassRefinement 激活 my_method 细化。
  2. MyClass.new.my_method被执行。
  3. A method lookup 从确切的调用点开始:

When looking up a method for an instance of class C Ruby checks:

  • If refinements are active for C, in the reverse order they were activated
    • The prepended modules from the refinement for C
    • The refinement for C
    • The included modules from the refinement for C
  • The prepended modules of C
  • C
  • The included modules of C
  1. 优化 有效,并且 my_method returns 来自优化的代码 "refined my_method()"
  2. MyClass.new.another_method被执行。
  3. method lookup 从确切的调用点开始。
  4. 细化 在调用的这一点上处于活动状态 ,但 another_method 不是细化,因此 Ruby 在中查找 another_method class MyClass 并找到它。
  5. 在 class 方法 another_method 中,找到并调用方法 my_method
  6. method lookup 从确切的调用点开始。
  7. 在调用点,没有任何改进处于活动状态,因为没有调用 using 行上方 (即物理上先于),其中 my_method 被调用。 Ruby 继续在 class MyClass 中寻找 my_method 并找到它。
  8. my_method returns 来自 class 方法的代码 "original my_method()"

我们可以做一个简单的比较。假设我有一个隔离的 file.rb,代码如下:

puts puppy
puppy = 'waggle'

puppy未定义前不能使用。该变量是词法范围的,其使用取决于其定义在隔离 file.rb.

中的位置

类似地,细化只有在前一行(或源代码文件中物理上的某处)通过using激活后才能被调用。细化为lexically scoped.

From Wikipedia

In languages with lexical scope (also called static scope), name resolution depends on the location in the source code and the lexical context, which is defined by where the named variable or function is defined...

Lexical resolution can be determined at compile time, and is also known as early binding, while dynamic resolution can in general only be determined at run time, and thus is known as late binding.


this article 的最后一节讨论了您关于优化的具体问题。作者还解释了 using 语句在文件中的物理位置如何确定优化是否处于活动状态。