Ruby改进了陷阱

kst*_*tis 5 ruby metaprogramming refinements

在第2章" 改进 "部分的元编程Ruby 2中,我发现了以下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?
Run Code Online (Sandbox Code Playgroud)

据作者说:

但是,调用another_method 可能抓住你措手不及:即使你打电话another_methodusing,调用my_method本身发生之前using-所以它调用该方法的原始的,未精制的版本.

这完全让我失望.

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

任何人都可以提供更直观/更好的解释吗?

谢谢.

Dan*_*ger 5

我能找到的最好的解释来自文档

细化是在词汇范围上的。细化仅在调用 后在某个范围内有效using。该using语句之前的任何代码都不会激活细化。

这意味着您的优化方法必须在调用using. 重要的是方法调用的实际位置,而不是如何调用方法或从何处调用方法。


事情是这样的。

  1. usingusing MyClassRefinement激活my_method细化。
  2. MyClass.new.my_method被执行。
  3. 从确切的调用点开始进行方法查找:

当查找class CRuby 检查实例的方法时:

  • 如果细化已激活C,则按照激活的相反顺序
    • 来自细化的前置模块C
    • 细化为C
    • 细化后包含的模块C
  • 的前置模块C
  • C
  • 包含的模块C
  1. 细化处于活动状态,并my_method返回细化的代码"refined my_method()"
  2. MyClass.new.another_method被执行。
  3. 方法查找从确切的调用点开始。
  4. 细化在调用时处于活动状态,但不是细化,因此 Ruby在类中another_method查找并找到它。another_methodMyClass
  5. 在类方法内部,找到并调用another_method该方法。my_method
  6. 方法查找从确切的调用点开始。
  7. 在调用点,没有活动的细化,因为没有对调用using 的线上方(即物理上之前)的my_method调用。my_methodRuby继续在班级中寻找MyClass并找到了它。
  8. my_method从类方法返回代码"original my_method()"

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

puts puppy
puppy = 'waggle'
Run Code Online (Sandbox Code Playgroud)

puppy在定义之前不能使用。该变量具有词法作用域,其使用取决于其定义在isolated 中的位置file.rb

类似地,只有通过前一行(或源代码文件中物理上之前的某个位置)激活细化才能被调用。using细化是在词法范围内的

来自维基百科

在具有词法作用域(也称为静态作用域)的语言中,名称解析取决于源代码和词法上下文中的位置,词法上下文由定义命名变量或函数的位置定义...

词法解析可以在编译时确定,也称为早期绑定,而动态解析一般只能在运行时确定,因此称为后期绑定


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