gpt4 book ai didi

Ruby 元类疯狂

转载 作者:数据小太阳 更新时间:2023-10-29 06:38:03 24 4
gpt4 key购买 nike

我卡住了。我正在尝试动态定义一个类方法,但我无法全神贯注于 ruby​​ 元类模型。考虑以下类:

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

显然,这两种方法都返回一个 Class 实例。但是这两个实例不一样。他们也有不同的祖先:

Example.meta.ancestors            # => [Class, Module, Object, Kernel]
Example.class_instance.ancestors # => [Example, Object, Kernel]

区分元类和类实例有什么意义?

我想通了,我可以发送 :define_method 到元类来动态定义一个方法,但是如果我尝试将它发送到类实例,它将无法工作。至少我可以解决我的问题,但我仍然想了解为什么它会这样工作。

2010 年 3 月 15 日 13:40 更新

下列假设是否正确。

  • 如果我有一个调用 self.instance_eval 并定义方法的实例方法,它只会影响该类的特定实例。
  • 如果我有一个调用 self.class.instance_eval 的实例方法(这与调用 class_eval 相同)并定义了一个方法,它将影响该特定类的所有实例,从而产生一个新的实例方法。
  • 如果我有一个调用 instance_eval 的类方法并定义了一个方法,它将为所有实例生成一个新的实例方法。
  • 如果我有一个类方法调用元/本征类上的 instance_eval 并定义一个方法,它将产生一个类方法。

我觉得这对我来说开始有意义了。如果类方法中的 self 指向本征类,那肯定会限制您的可能性。如果是这样,就不可能从类方法内部定义实例方法。对吗?

最佳答案

当您使用 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

至于上面的区别,你混淆了两件事:

您定义的元类,在 Ruby 社区中称为 singelton classeigen class。该单例类是您可以向其添加类(单例)方法的类。

至于你试图使用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方法没用,去掉就好了。

无论如何,我建议您阅读 this post掌握 Ruby 反射系统的一些概念。

更新

我建议您阅读这篇精彩的文章:Fun with Ruby's instance_eval and class_eval ,不幸的是,class_evalinstance_eval 令人困惑,因为它们在某种程度上违背了它们的命名!

Use ClassName.instance_eval to define class methods.

Use ClassName.class_eval to define instance methods.

现在回答你的假设:

If I have an instance method which calls self.instance_eval and defines a method, it will only affect the particular instance of that class.

是的:

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) #=> []

If I have an instance method which calls self.class.instance_eval (which would be the same as calling class_eval) and defines a method it will affect all instances of that particular class resulting in a new instance method.

没有 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

If I have a class method which calls instance_eval and defines a method it will result in a new instance method for all instances.

没有:

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

If I have a class method which calls instance_eval on the meta/eigen class and defines a method it will result in a class method.

嗯,不,那会做出如此复杂的东西,因为它将向单例类添加单例方法,我认为这不会有任何实际用途。

关于Ruby 元类疯狂,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2446428/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com