猴子补丁vs class_eval?
class String def hello "world" end end String.class_eval { def world "hello" end } "a".world => "hello" "b".hello => "world"
他们似乎做了同样的事情 – 向现有类添加方法。 那有什么区别?
使用class_eval
您可以做更多动态的事情:
>> met = "hello" #=> "hello" >> String.class_eval "def #{met} ; 'hello' ; end" #=> nil >> "foo".hello #=> "hello"
class_eval在概念上做类重新打开(或猴子修补)。 主要是语法差异。 如果将字符串传递给class_eval
(如Michael的示例中所示),则字符串内部的语法与class String; ... end
语法大致相同class String; ... end
class String; ... end
如果传递block: String.class_eval { ... }
则比较如下:
- 在class_eval块内部外部局部变量是可见的
- 内部重新打开的类外部局部变量是不可见的
- 在class_eval内部,您不能将作用域的常量和类变量分配给该类
- 你可以在里面重新上课
知道其他差异会很有趣
其他答案都很好。 想要添加的是,当您希望引用类不是通过常量或修补特定对象时,可以使用class_eval
。
例如
huh = String class huh end SyntaxError: (eval):2: class/module name must be CONSTANT huh.class_eval <<-eof def mamma puts :papa end eof "asdff".mamma => papa
您可以使用class_eval
来修补特定对象,而不会影响整个根类。
obj = "asd" obj.singleton_class.class_eval <<-eof def asd puts "gah" end undef_method :some_method
以上内容与:
class << obj ... end
通过某种用法, instance_eval
会有稍微不同的行为。
我发现这个问题和答案很有趣: 如何在方法中修补ruby类
还有关于instance_eval
vs class_eval
问题,但我没有方便的链接。