Ruby MetaProgramming中的一个混乱的情况 [英] a confusing case in Ruby MetaProgramming

查看:152
本文介绍了Ruby MetaProgramming中的一个混乱的情况的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Ruby MetaProgramming的开始学习者。当在irb中练习我的代码时,我遇到了这个问题。

  end 
a = A.new
b = class<<一个;自; end

b.instance_eval {def foo; puts foo'; end}
#=>工程b.foo

b.instance_eval {define_method:bar do;放置酒吧end}
#=>为什么这个工作a.bar而不是b.bar

最后的代码片段困惑了我。 / p>




感谢您的具体答案,但也许我没有清楚解释我的混乱。我真正想了解的是,为什么 define_method 在这些情况下表现如此不同:

  class A 
def foo1
p'foo1 from A'
end

define_method:bar1 do
p'bar1 from A'
end
end

a = A.new
a.foo1#=> 'foo1 from A'
a.bar1#=> 'bar1 from A'


a.instance_eval {def foo2; p'foo2 from a.metaclass'; end}
a.foo2#=> 'foo2 from a.metaclass'
a.instance_eval {define_method:bar2 do; p'bar2 from a.metaclass'; end}
#=> NoMethodError:undefined method`define_method'for#< A:0x000000016a2e70>

aa = class<<一个;自; end
aa.instance_eval {def foo3; p'foo3 from a.metaclass.metaclass'; end}
aa.foo3#=> 'foo3 from a.metaclass.metaclass'
aa.instance_eval {define_method:bar3 do; p'bar3 from a.metaclass.metaclss'; end}
aa.bar3#=> NoMethodError:undefined method`bar3'for#< Class:#< A:0x000000016a2e70>
a.bar3#=> 'bar3 from a.metaclass.metaclss'

我知道这不是在day-






得出结论:

  aa = class<<一个;自; end 

aa.instance_eval {def foo; puts'foo ..'; end}

#为aa定义一个singleton方法
aa.foo#=> 'foo ...'


aa.instance_eval {define_method:bar do; puts'bar ..'; end}
#equals
aa.class_eval {def bar; puts'bar ..'; end}

#都为a定义了一个singleton方法,
#定义了define_method和class_eval,都定义了instance_method
a.bar#=> 'bar ...'


解决方案

评论:



[从Pickaxe]方法Object#instance_eval允许你将self设置为某个任意对象,使用[self]评估一个块中的代码,然后重置自我。

和模块#define_method:在接收者中定义一个实例方法[self,它必须是一个(匿名)类或模块]。

  singleton_class_of_object_a = aa = class<<一个;自; end 
aa.instance_eval {def foo3; putsfoo3 from singleton class of a,self =#{self}; end}
aa.foo3#=> foo3 from singleton class of a,self =#< Class:#< A:0x007fc2e4049e68>
aa.instance_eval do
putsabout to define_method:bar3 in self =#{self}
define_method:bar3 do; putsbar3 from singleton class of a,self =#{self}; end
end#=> about to define_method:bar3 in self =#< Class:#< A:0x007fc2e4049e68>
a.bar3#=> bar3 from a singleleton class of a,self =#< A:0x007fc2e4049e68>

define_method:bar3 of singleton_class_of_object_a(一个匿名类,见下文),因此定义了该类的实例方法,因此bar3成为a的单例方法。正如我在上一个答案中所说的,它相当于直接在对象上定义:

  def a.bar4; puts'bar4 from a singleton class a'end 
a.bar4#=> bar4 from singleton class a

p a.singleton_methods.sort#=> [:bar3,:bar4,:foo2]
p a.methods(false).sort#=> [:bar3,:bar4,:foo2]

c $ c> a = A.new ,实例 a 的字段类指向类 A

class<< a def a.bar4 ,Ruby创建一个匿名类,实例的字段类 a 现在指向此匿名类,并从 A

此上下文中定义的方法 def define_method 进入匿名类的方法表。


I'm a start learner about Ruby MetaProgramming. when practicing my code in irb, I met this problem.

class A; end
a = A.new
b = class << a; self; end

b.instance_eval { def foo; puts 'foo'; end }
# => works for b.foo

b.instance_eval { define_method :bar do; puts 'bar'; end }
# => WHY this one works for a.bar rather than b.bar

The last code fragment confused me.


Thanks for your specific answers, but maybe I didn't explain my confusion clearly. What I'm really trying to understand is why define_method behaves so differently in these cases, here:

class A
  def foo1
    p 'foo1 from A'
  end 

  define_method :bar1 do
    p 'bar1 from A'
  end 
end

a = A.new
a.foo1 # => 'foo1 from A'
a.bar1 # => 'bar1 from A'


a.instance_eval { def foo2; p 'foo2 from a.metaclass'; end }
a.foo2 # => 'foo2 from a.metaclass'
a.instance_eval { define_method :bar2 do; p 'bar2 from a.metaclass'; end }
# => NoMethodError: undefined method `define_method' for #<A:0x000000016a2e70>

aa = class << a; self; end
aa.instance_eval { def foo3; p 'foo3 from a.metaclass.metaclass'; end }
aa.foo3 # => 'foo3 from a.metaclass.metaclass'
aa.instance_eval { define_method :bar3 do; p 'bar3 from a.metaclass.metaclss'; end }
aa.bar3 # => NoMethodError: undefined method `bar3' for #<Class:#<A:0x000000016a2e70>>
a.bar3 # => 'bar3 from a.metaclass.metaclss'

I know that this doesn't come up in day-to-day coding, but I want to make my mind clear.


make a conclusion:

aa = class << a; self; end 

aa.instance_eval { def foo; puts 'foo..'; end }

# defines a singleton-method for aa
aa.foo # => 'foo...'


aa.instance_eval { define_method :bar do; puts 'bar..'; end }
# equals
aa.class_eval { def bar; puts 'bar..'; end }

# both define a singleton-method for a,
# as define_method and class_eval both define instance_method
a.bar # => 'bar...'

解决方案

In addition to all other comments :

[from the Pickaxe] The method Object#instance_eval lets you set self to be some arbitrary object, evaluates the code in a block with [self], and then resets self.
And Module#define_method : Defines an instance method in the receiver [self, which must be a (anonymous) Class or Module].

singleton_class_of_object_a = aa = class << a; self; end
aa.instance_eval { def foo3; puts "foo3 from singleton class of a, self=#{self}"; end }
aa.foo3 # => foo3 from singleton class of a, self=#<Class:#<A:0x007fc2e4049e68>>
aa.instance_eval do
    puts "about to define_method :bar3 in self=#{self}"
    define_method :bar3 do; puts "bar3 from singleton class of a, self=#{self}"; end
end # => about to define_method :bar3 in self=#<Class:#<A:0x007fc2e4049e68>>
a.bar3 # => bar3 from singleton class of a, self=#<A:0x007fc2e4049e68>

define_method :bar3 is executed in the context of singleton_class_of_object_a (an anonymous class, see below), thus defines an instance method of that class, hence bar3 becomes a singleton method of a. As already said in my previous answer, it is equivalent to defining directly on the object :

def a.bar4; puts 'bar4 from singleton class of a' end
a.bar4 # => bar4 from singleton class of a

p a.singleton_methods.sort # => [:bar3, :bar4, :foo2]
p a.methods(false).sort # => [:bar3, :bar4, :foo2]  


After a = A.new, the field class of instance a points to class A.
With class << a or def a.bar4, Ruby creates an anonymous class, the field class of instance a now points to this anonymous class, and from there to A.
Methods defined in this context with def or define_method go into the methods table of the anonymous class.

这篇关于Ruby MetaProgramming中的一个混乱的情况的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆