-
20-09-2019 - |
题
我卡住了我想要动态定义一类的方法,我不能理解的红宝石元类型。考虑以下几类:
class Example
def self.meta; (class << self; self; end); end
def self.class_instance; self; end
end
Example.class_instance.class # => Class
Example.meta.class # => Class
Example.class_instance == Example # => true
Example.class_instance == Example.meta # => false
显然这两种方法返回的一个实例类。但这两个实例 是不一样的。他们也有不同的祖先:
Example.meta.ancestors # => [Class, Module, Object, Kernel]
Example.class_instance.ancestors # => [Example, Object, Kernel]
什么是在作出之间的差异元类和类实例?
我想通了,我可以 send :define_method
向元类以动态定义的方法,但是如果我尝试送到这类实例,它不会的工作。至少我可以解决我的问题,但我仍然想要了解为什么是这种方式工作。
更新Mar15 2010年13:40
是下述假设正确的。
- 如果我有一个实例的方法,其中要求自己。了instance_eval和定义的方法,它只会影响的具体实例。
- 如果我有一个实例的方法,其中要求自己。类。了instance_eval(这将是一样叫class_eval)和定义的方法会影响的所有实例中,特定类造成一个新的实例的方法。
- 如果我有一个类方法,其中要求了instance_eval和定义了一种方法,它将导致一个新的实例法为所有实例。
- 如果我有一个类方法,其中要求了instance_eval元/特征类和定义了一种方法,它会导致类方法。
我觉得它开始有意义的给我。这当然会限制你的可能性,如果自内部的一个类方法要点的特征类。如果那么它将是不可能的定义的一个实例的方法从内部一类的方法。是正确的?
解决方案
界定一种单独方法动态是简单当你使用 instance_eval
:
Example.instance_eval{ def square(n); n*n; end }
Example.square(2) #=> 4
# you can pass instance_eval a string as well.
Example.instance_eval "def multiply(x,y); x*y; end"
Example.multiply(3,9) #=> 27
至于区别上,你是混乱的2件事:
Meta类定义的你是什么叫Ruby社会 singelton类 或 征类.这一单一类,可以添加类(单独)方法。
作为类实例是试图定义使用 class_instance
方法,是没有什么,但这类本身,为了证明这一点,只是试图增加一个实例法的类 Example
看看 class_instance
方法由你定义的回报类 Example
本身通过检查存在,方法是:
class Example
def self.meta; (class << self; self; end); end
def self.class_instance; self; end
def hey; puts hey; end
end
Example.class_instance.instance_methods(false) #=> ['hey']
无论如何要求和它给你,当你想添加类方法,只要它们添加到那个阶类。作为 class_instance
方法是无用的,只是删除它。
无论如何我建议你读 这个职位 掌握一些概念的红宝石的反射系统。
更新
我建议你读这个漂亮的员额: 有趣与红宝石了instance_eval和class_eval,
不幸的是 class_eval
和 instance_eval
很容易混淆,因为他们不知何故对他们的命!
Use ClassName.instance_eval to define class methods.
Use ClassName.class_eval to define instance methods.
现在回答你的假设:
如果我有一个方法,该方法的实例 呼叫的我。了instance_eval和定义 方法,它只会影响 特别的实例。
是的:
class Foo
def assumption1()
self.instance_eval("def test_assumption_1; puts 'works'; end")
end
end
f1 = Foo.new
f1.assumption1
f1.methods(false) #=> ["test_assumption_1"]
f2 = Foo.new.methods(false) #=> []
如果我有一个方法,该方法的实例 呼叫的我。类。了instance_eval(其中 将同样为呼唤 class_eval)和界定一种方法 将影响到所有的实例, 特定类造成一个新的 实例的方法。
没有 instance_eval
在这方面将定义的单独方法(未实例中的)关的类本身:
class Foo
def assumption2()
self.class.instance_eval("def test_assumption_2; puts 'works'; end")
end
end
f3 = Foo.new
f3.assumption2
f3.methods(false) #=> []
Foo.singleton_methods(false) #=> ["test_assumption_2"]
为此,以工作换 instance_eval
与 class_eval
以上。
如果我有一个类方法,该方法通话 了instance_eval和定义的一个方法 会导致一种新的方法实例 所有实例。
不:
class Foo
instance_eval do
def assumption3()
puts 'works'
end
end
end
Foo.instance_methods(false) #=> []
Foo.singleton_methods(false) #=> ["assumption_3"]
这将使单独方法、不实例的方法。为此,以工作换 instance_eval
与 class_eval
以上。
如果我有一个类方法,该方法通话 了instance_eval元/特征类 而定义了一种方法,它会导致 一个类方法。
哦,不,这将使如此复杂的东西,因为它将增加单独的方法的单独课,我不认为会有任何实际使用。
其他提示
如果定义上的一个方法 类, 它可以援用上它的 对象.它是一个 实例的方法.
class Example
end
Example.send :define_method, :foo do
puts "foo"
end
Example.new.foo
#=> "foo"
如果定义上的一个方法 元类, 它可以援引上 类.这是类似的概念 类方法 或静态的方法在其他语言。
class Example
def self.metaclass
class << self
self
end
end
end
Example.metaclass.send :define_method, :bar do
puts "bar"
end
Example.bar
#=> "bar"
的 的原因 这元类存在是因为你可以做到这红宝石:
str = "hello"
class << str
def output
puts self
end
end
str.output
#=> "hello"
"hi".output
# NoMethodError
正如你可以看到,我们定义的一个方法只适用于 一个 实例。我们定义的这个方法上称为 元类.在方法查找链,元类访问之前,首先寻找对象的类。
如果我们取代目的类型 String
有一个目的类型 Class
, 你能想象为什么这意味着我们只是定义上的一个方法 具体 类,不是所有的类别。
之间的差异目前情况下和 self
是微妙的,可以 阅读更多 如果你有兴趣。