Ruby精炼细微之处
这里有关于
ruby中当前优化实现的很好的文档:
http://ruby-doc.org//core-2.2.0/doc/syntax/refinements_rdoc.html, 但是有一些奇怪的角落案例. 首先,include模块与使用模块正交(一个包括模块的实例方法,另一个激活细化).但是有一个技巧包括一个改进模块本身,请参阅 def to_module(klass) Module.new do #note that we return the refinement module itself here return refine(klass) { yield if block_given? } end end class Base def foo "foo" end end class Receiver include to_module(Base) { def foo "refined " + super end } end Receiver.new.foo #=> "refined foo" 奇怪的是,这个改进模块不能与使用一起使用! m=to_module(Base) {} m.class #=> Module using m #=>TypeError: wrong argument type Class (expected Module) 因此,仅使用细化模块的封闭模块. def ref_module1(klass) Module.new do refine(klass) { yield } end end class Receiver1 using ref_module1(Base) { def foo "refined " + super end } def bar Base.new.foo end end Receiver1.new.bar #=> NoMethodError: super: no superclass method `foo' 我们看到Receiver1仍然使用Bar#foo而不是精炼方法. def ref_module2(klass,&b) Module.new do refine(klass) { module_eval(&b) } end end class Receiver2 using ref_module2(Base) { def foo "refined " + super end } def bar Base.new.foo end end Receiver2.new.bar #=> "refined foo" 我不太明白为什么module_eval在这里工作而不是yield方法.在细化块内部,’default_definee’是细化模块,因此将’default_definee’置于self =’细化模块’的module_eval不应该影响它.事实上,在开头的’include’示例中,当我使用module_eval或直接yield时,我得到相同的结果. 谁能解释这种行为? 解决方法
上下文(或绑定)是module_eval工作的原因,而yield不在你的上一组示例中.它实际上与细化无关,如下所示.
从module_eval开始: class Foo def run(&block) self.class.module_eval(&block) end end foo = Foo.new foo.run { def hello "hello" end } puts foo.hello # => "hello" puts hello => # '<main>': undefined method 'hello' for main:Object (NameError) 在Foo#run中,我们在Foo上调用module_eval.这将上下文(self)切换为Foo.结果很像我们原来在类Foo中有简单定义的hello. 现在让我们来看看收益率: class Foo def run yield end end foo = Foo.new foo.run { def hello "hello" end } puts hello # => "hello" puts foo.hello # => '<main>': private method 'hello' called for ... yield只是在原始上下文中调用块,在本例中它将是< main>.调用块时,最终结果与通常在顶层定义方法的结果完全相同: class Foo def run yield end end foo = Foo.new def hello "hello" end puts hello # => "hello" puts foo.hello # => '<main>': private method 'hello' called for ... 您可能会注意到foo似乎在yield示例中有hello方法.这是将hello定义为顶层方法的副作用.事实证明< main>它只是Object的一个实例,定义顶级方法实际上只是在Object上定义私有方法,几乎??所有其他方法都会继承.您可以通过打开irb并运行以下命令来查看: self # => main self.class # => Object def some_method end "string".method(:some_method) # => #<Method: String(Object)#some_method> 现在回到你的例子. 以下是yield示例中发生的情况: def ref_module1(klass) Module.new do refine(klass) { yield } end end class Receiver1 # like my yield example,this block is going to # end up being invoked in its original context using ref_module1(Base) { def foo "I'm defined on Receiver1" end } def bar # calling foo here will simply call the original # Base#foo method Base.new.foo end end # as expected,if we call Receiver1#bar # we get the original Base#foo method Receiver1.new.bar # => "foo" # since the block is executed in its original context # the method gets defined in Receiver1 -- its original context Receiver1.new.foo # => "I'm defined on Receiver1" 对于module_eval,它适用于您的示例,因为它会导致块在新模块的上下文中运行,而不是在Receiver1类上运行. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |