猴子补丁vs class_eval?

Lai*_*uan 14 ruby monkeypatching metaprogramming

class String
  def hello
    "world"
  end
end

String.class_eval {
  def world
    "hello"
  end
}

"a".world
=> "hello"
"b".hello
=> "world"
Run Code Online (Sandbox Code Playgroud)

他们似乎做了同样的事情 - 向现有类添加方法.那有什么区别?

Mic*_*ohl 13

随着class_eval你可以做更多动态的事情:

>> met = "hello" #=> "hello"
>> String.class_eval "def #{met} ; 'hello' ; end" #=> nil
>> "foo".hello #=> "hello"
Run Code Online (Sandbox Code Playgroud)


Ale*_*xey 13

class_eval在概念上做类重新打开(或猴子修补).主要是语法差异.如果你传递字符串class_eval(如迈克尔的例子),你在字符串中的语法大致相同class String; ... end.如果你传递阻止:String.class_eval { ... }它比较如下:

  • 在class_eval块内部外部局部变量是可见的
  • 内部重新打开的类外部局部变量是不可见的
  • 在class_eval内部,您不能将作用域的常量和类变量分配给该类
  • 你可以在里面重新上课

了解其他差异会很有趣