Ruby继承和类型

Ruby继承和类型,ruby,class,module,typeerror,dynamic-typing,Ruby,Class,Module,Typeerror,Dynamic Typing,我在Ruby的一些基本概念上遇到了问题,特别是超类的子类的可互换性 根据关于类的Ruby文档,“类”继承自“模块”。 但是,当尝试使用模块关键字重新打开用关键字类定义的类时,会出现类型错误,表明该类不是模块 class MyClassTest end module MyClassTest end # => TypeError: MyClassTest is not a module 这个问题围绕子类和子类型进行了一些很好的讨论,但我认为它让我想到了更多的问题: 一般来说,由于Ruby

我在Ruby的一些基本概念上遇到了问题,特别是超类的子类的可互换性

根据关于类的Ruby文档,“类”继承自“模块”。

但是,当尝试使用
模块
关键字重新打开用关键字
定义的类时,会出现类型错误,表明该类不是模块

class MyClassTest end
module MyClassTest end # => TypeError: MyClassTest is not a module
这个问题围绕子类和子类型进行了一些很好的讨论,但我认为它让我想到了更多的问题:

一般来说,由于Ruby是动态类型的,我对类型错误的存在感到困惑

具体地说,在本例中,我特别困惑Ruby继承如何导致类型错误,其中子类不能替换超类。在我看来,子类化相当于Ruby中的子类型化,因为子类将继承超类的接口(方法和公共属性)

我目前的猜测是,当某些断言失败时,核心Ruby库会引发TypeError,而这些TypeError不一定与Ruby的动态类型系统有任何关系,也就是说,类型在Ruby中不是一流的概念。链接的SO问题提出了关于多类继承的菱形问题的优秀观点,因此Ruby在使用
module
class
关键字时会阻止模块和类的可互换使用是有意义的。尽管如此,我还是觉得我对Ruby的理解不一致

当需要“模块”对象时,“类”输入如何导致类型错误?

基本断言是

  • Class
    是一个
    Class
    Class.is_a?(Class)#=>true
  • Class
    是一个
    模块
    Class.is_a?(模块)#=>true
  • class
    的实例是
    class
    class.new.is_a?(class)#=>true
  • class
    的一个实例是
    模块
    class.new.is_a?(模块)#=>true
  • 模块
    是一个
    模块.是吗?(类)#=>真的
  • 由于
    模块
    是一个
    模块
    Module.is_a?(Module)#=>true
  • 模块
    的实例是
    模块
    模块.new.is_a?(模块)#=>true
  • 但是,类
    模块
    的实例不是
    模块.new.is_a?(类)#=>false
  • class
    的实例是
    class
    的实例,但不是类
    模块的实例(
    class.new.instance_of?(Module)#=>false
模块
是类
模块
实例的声明,正如
是类
实例的声明一样

如果这是一种方法,它可能看起来像

def module(name,&block)
  raise TypeError if defined?(name) && !const_get(name).instance_of?(Module)
  obj = defined?(name) ? const_get(name) : const_set(name, Module.new)
  obj.instance_eval(&block)
end
TypeError
的存在是为了防止歧义

与使用
class MyClassTest
的情况一样,您已经创建了类
class
的实例,该实例称为
MyTestClass

如果您也被允许在相同的全局上下文中使用
模块MyTestClass
,那么在使用过程中,如果调用
MyClassTest
时我将调用
Class
模块,我将不知道

基本(非常基本)的区别是
类可以实例化(有实例),而
模块不能实例化

比如说

Class.new.new #creates an instance of the anonymous class created by Class.new
Module.new.new # results in NoMethodError

我认为第一个混淆点是用法和定义之间的区别

以下代码定义了一个类:

class C; end
如果我看到上面的代码,我希望以后能够实例化C:

C.new
但是,假设C已经被定义为一个模块:

# In one file:
module C; end

# Later in a different file:
class C; end    # C is actually a module

C.new           # fails
Ruby在C被重新定义为类时解决了问题(C的定义冲突),而不是允许程序继续使用C

尽早发现问题的好处通常是越早发现错误,就越容易找到并修复其根本原因(在本例中,也许C毕竟应该是一个类,因此真正的问题是
模块C
定义)

我认为,你的第二个问题是,为什么一个类不能总是被用作一个模块,例如为什么禁止以下内容:

class C; end
class A
  include C
end
我认为,答案是编程语言从概念开始,然后使用各种构造实现概念。我们可以如下描述类和模块:

  • 类表示具有数据和行为的对象(经典的OOP定义)
  • 模块是行为的集合
include
关键字使用模块的行为扩展类。原则上,只取一个类的方法并将它们添加到另一个类是可能的。但是这个操作没有意义,因为类是一个对象,它的行为同时存在。仅仅采取这种行为就违反了班级的概念


在这个问题上,还有其他一些编程语言持不同的立场。例如,在JavaScript中,任何函数都可以从任何类中取出,并与任何其他类的实例一起调用。这在某些情况下很方便,在其他情况下很难调试。

在JavaScript类中并不是真正的问题。JavaScript中的类是第一类函数的语法糖,这些函数可能定义也可能不定义其他函数。然而,基于这些断言:“类是一个模块(Class.is_a?(Module)#=>true)”,“类的实例是一个模块(Cl
class C; end
class A
  include C
end