我卡住了我想要动态定义一类的方法,我不能理解的红宝石元类型。考虑以下几类:

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_evalinstance_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_evalclass_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_evalclass_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 是微妙的,可以 阅读更多 如果你有兴趣。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top