这个Ruby用Class.new做什么来创建类,

时间:2014-08-19 16:59:23

标签: ruby metaprogramming

请考虑以下代码:

module MyClass
 def foo
  "method"
 end
end

现在,我可以通过常规

实例化一个新类
@my_new_class = MyClass.new

或者,我可以做一些元编程魔术

@my_new_class = Class.new { include MyClass }.send :new 

问题是两者之间有什么区别?

2 个答案:

答案 0 :(得分:4)

上面的代码(几乎)等同于:

MyNewClass = Class.new { include MyClass }
@my_new_class = MyNewClass.new

这就像

class MyNewClass
  include MyClass
end
@my_new_class = MyNewClass.new

使用Class.new即时声明匿名新类:

  

使用给定的超类创建一个新的匿名(未命名)类(如果没有给出参数,则创建Object)。您可以通过将类对象赋值给常量来为类赋予名称。

     

如果给出了一个块,它将传递给该类对象,并使用class_eval在该类的上下文中计算该块。

答案 1 :(得分:1)

您对该模块的命名类似于sue = Boy.new,因此我已将其更改为适合其遗产。我相信你不会介意。

module MyModule
 def foo
  "method"
 end
end

让我们先收集一些基本信息:

Module.class                       #=> Class
Module.ancestors                   #=> [Module, Object, Kernel, BasicObject]
Module.methods.include? :new       #=> true
Module.new                         #=> #<Module:0x000001022050c8>

如您所见,ModuleClass的一个实例,其方法为:new。现在让我们看看你创建的模块:

MyModule.class                     #=> Module
MyModule.ancestors                 #=> [MyModule]
MyModule.instance_methods          #=> [:foo]
MyModule.methods.include? :new     #=> false

它是Class的一个实例,只有一个实例方法(:foo),您创建了它。它没有祖先,所以它不会继承任何方法。重要的是,Module的实例没有方法:new。因此,如果我们尝试调用它,结果是可预测的:

my_new_module = MyModule.new
  #=> NoMethodError: undefined method `new' for MyModule:Module

方法#1的故事结束。

现在收集与您的第二种方法相关的信息:

my_new_instance = Class.new { include MyModule }.send :new

我已将变量my_new_class的名称更改为my_new_instance,原因很快就会显现出来。我们可以分两步编写,如下所示:

Class1 = Class.new { include MyModule }
Class1.instance_methods.include? :foo #=> true
Class1.methods.include? :new          #=> true
Class1.method(:new).owner             #=> Class

因此,我们确认Class1已正确构建,具有实例方法:foo并从:new继承了类方法Class

my_new_instance = Class1.new          #=> #<Class1:0x00000101a1edc8>
my_new_instance = Class1.send :new    #=> #<Class1:0x0000010204eab8>
my_new_instance.class                 #=> Class1
my_new_instance.is_a? Class           #=> false
my_new_instance.foo                   # (prints) "method"
my_new_instance.send :foo             # (prints) "method"

我们看到my_new_instance确实是Class1的一个实例(可以通过所示的任一方法创建),并以所示的两种方式之一调用:foo。< / p>