这个Ruby对Class.new做了什么来创建类, 请考虑以下代码: module MyClass def foo "method" end end

这个Ruby对Class.new做了什么来创建类, 请考虑以下代码: module MyClass def foo "method" end end,ruby,metaprogramming,Ruby,Metaprogramming,现在,我可以用通常的方法实例化这个类的一个新类 @my_new_class = MyClass.new 或者,我可以做一些元编程魔术 @my_new_class = Class.new { include MyClass }.send :new 问题是这两者之间的区别是什么?上述代码(几乎)相当于: MyNewClass = Class.new { include MyClass } @my_new_class = MyNewClass.new 就像 class MyNewClass

现在,我可以用通常的方法实例化这个类的一个新类

@my_new_class = MyClass.new
或者,我可以做一些元编程魔术

@my_new_class = Class.new { include MyClass }.send :new 
问题是这两者之间的区别是什么?

上述代码(几乎)相当于:

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

class MyNewClass
  include MyClass
end
@my_new_class = MyNewClass.new
使用动态声明匿名新类:

使用给定的超类(如果未给定参数,则使用对象)创建一个新的匿名(未命名)类。通过将类对象指定给常量,可以为类命名

如果给定一个块,它将被传递给类对象,并使用
class\u eval
在该类的上下文中计算该块

上述代码(几乎)相当于:

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

class MyNewClass
  include MyClass
end
@my_new_class = MyNewClass.new
使用动态声明匿名新类:

使用给定的超类(如果未给定参数,则使用对象)创建一个新的匿名(未命名)类。通过将类对象指定给常量,可以为类命名

如果给定一个块,它将被传递给类对象,并使用
class\u eval
在该类的上下文中计算该块


您对模块的命名类似于
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>
它是
的一个实例,只有一个您创建的实例方法(
:foo
)。它没有祖先,因此不继承任何方法。重要的是,
模块的实例没有方法
: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_实例
,原因很快就会显现出来。我们可以分两步编写,如下所示:

Class1 = Class.new { include MyModule }
Class1.instance_methods.include? :foo #=> true
Class1.methods.include? :new          #=> true
Class1.method(:new).owner             #=> Class
因此,我们确认
Class1
构造正确,具有实例方法
:foo
,并从
类继承类方法
:new

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.new#=>#
我的新实例=Class1.send:new#=>#
my_new_instance.class#=>Class1
我的新例子是a吗?类#=>假
my_new_instance.foo#(打印)“方法”
my_new_instance.send:foo#(prints)“方法”

我们看到,
my_new_实例
确实是
Class1
的一个实例(它可以通过所示的任何一种方法创建),并以所示的两种方式调用
:foo

您对模块的命名类似于
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>
它是
的一个实例,只有一个您创建的实例方法(
:foo
)。它没有祖先,因此不继承任何方法。重要的是,
模块的实例没有方法
: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_实例
,原因很快就会显现出来。我们可以分两步编写,如下所示:

Class1 = Class.new { include MyModule }
Class1.instance_methods.include? :foo #=> true
Class1.methods.include? :new          #=> true
Class1.method(:new).owner             #=> Class
因此,我们确认
Class1
构造正确,具有实例方法
:foo
,并从
类继承类方法
:new

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.new#=>#
我的新实例=Class1.send:new#=>#
my_new_instance.class#=>Class1
我的新例子是a吗?类#=>假
my_new_instance.foo#(打印)“方法”
my_new_instance.send:foo#(prints)“方法”

我们看到,
mynew\u实例
确实是
Class1
的一个实例(可以通过所示的任何一种方法创建),并以所示的两种方式调用
:foo

您不能执行第二个示例:
TypeError:错误的参数类型类(预期模块)
。关键字
include
需要一个模块,看起来是。输入错误。我的意思是只需要一个模块。很好的捕获。编辑后,您无法执行第一个示例(
NoMethodError:MyClass:Module的未定义方法“new”)。无法执行第二个示例:
TypeError:Error参数类型类(预期模块)
。关键字
include
需要一个模块,看起来是。输入错误。我的意思是只需要一个模块。很好的捕获。编辑后,您无法执行第一个示例(
NoMethodError:undefined method'new',for MyClass:Module
)。