在编程语言理论中,子类型(动名词,)是一种类型多态的形式。这种形式下,子类型(名词,)可以替换另一种相关的数据类型(超类型,)。也就是说,针对超类型元素进行操作的子程序、函数等程序元素,也可以操作相应的子类型。如果 S 是 T 的子类型,这种子类型关系通常写作 S number 的语言。在第一种情况下,整数类型将是浮点数类型的子类型;在第二种情况下,这两个类型都是 number 的子类型而相互之间无子类型关系。
编程者可利用子类型来以比没有它更抽象的方式来写代码。考虑下面的例子:
function max (x as number, y as number) is
if x number 的子类型,则二者任何类型都可以传递给这个函数。为此,子类型经常被认为是一种形式的多态性。上述例子也可以比较于 C++ 语言的模板。
在类型论中,子类型关系经常写为 <:,有着 A<:B 意味着 A 是 B 的子类型。在类型论中子类型可用如下事实来特征化,如果 A<:B,类型 A 的任何表达式也可被给予类型 B;立法这个特征化的形式类型规则叫做“包容”规则。
子类型方案
类型理论研究者区分两类类型系统:
***',在其中只有类型声明的名字相同才算是相同类型,子类型关系必须被显式声明。C, C++, C#, Java, Objective-C等语言均属于这类。
***',在其中两种类型的结构组成决定了一种类型是否是另一种类型的子类型。
上面描述的基于类的面向对象子类型描述是名义的;面向对象的结构子类型规则可以声称,如果类型 A 的一个对象能处理类型 B 的对象能处理的所有消息(就是说,如果它们定义都同样的方法),则 A 是 B 的子类型,不管二者任何一个是否从继承自其他对象。不是对象类型的类型的健壮的结构子类型规则也是周知的。
带有子类型的编程语言实现可分为两大类:
如果 A<:B,类型 A 的任何值的表示也表示类型 B* 的相同值,则为“包含实现”(inclusive implementation)。
类型 A 的值可自动的转换成类型 B* 的值,则为“强制实现”( coercive implementation)。即类型强制转换之意。
在面向对象语言中子类型所导致的子类型通常是包含的;联系整数和浮点数的子类型关系,它们有不同表示,通常是强制的。
在定义子类型关系的几乎所有类型系统中,它是自反的(意味着对于任何类型 A 有 A<:A)和传递的(意味着如果 A<:B 并且 B<:C 则 A<:C)。这得到了在类型上的预序。
记录类型
记录是命名的域(field)的集合。记录类型(types of records)的子类型化包括宽度与深度两种方式。
- 宽度子类型化(width subtyping):给记录增加更多的域。
- 深度子类型化(depth subtyping):把超类型(supertype)的域替换为域的子类型。这仅能用于只读(immutable)记录。
函数类型
对于函数类型T1 → T2,其子类型为S1 → S2,则T1 1且S2 2。参数类型S1 → S2为逆变,返回类型为协变。
允许副作用的语言,如大部分面向对象语言,子类型化还不足以保证安全在另一个上下文中使用。行为子类型化要求保持不变。
可变引用(mutable reference)的子类型化类似于函数参数与返回值的处理。只写引用是逆变的;只读引用是协变的;可变引用是不变的。
类型强制
在强制子类型化系统(coercive subtyping system),子类型通过从子类型到超类型的隐式类型转换函数得以定义。对于每个子类型关系 (S S → T(s)具有类型T。类型强制函数可以复合:如果S T → U ∘ coerceS → T)。类型到其自身的coerceT → T是同一函数idT
参考文献
引用
来源
- Object-Oriented Software Construction by Bertrand Meyer
外部链接
参见
- 派生类型是给出新类型但结构上同于最初类型的类型。依赖于类型系统,它可以是也可以不是子类型。
- 基于类的编程有混淆了子类型和子类导致的问题的一个例子。
评论 (0)