PL真有意思(五):数据类型 (2)

按照指称的观点,一个类型就是一组值,一个值具有某个类型的条件是他属于这个值集合,一个对象具有某个类型的条件是他的值保证属于这个值集合

构造的

从构造的观点看,一个类型或者是以一小组内部类型,或者是通过对一个或几个更简单些的类型,应用某个类型的构造符构造出来的

基于抽象的

从基于抽象的角度来看,一个类型就是一个接口,由一组定义良好而且具有相互协调的语义的操作组成。

类型的分类

在不同语言里,有关类型的术语也不相同,这里说的通常都是常用的术语,大部分语言多提供的内部类型差不多就是大部分处理器所支持的类型:整数、字符、布尔和实数。

一般语言规范中都会规定数值类型的精度问题,以及一些字符的编码规定。通常特殊的一个数值类型是枚举类型,具体的语法在不同的语言中略有差异,但是其也都是一个目的(用一个字符友好的表示一个数值)。

关于枚举类型,由一组命名元素组成。在C中可以这样写:

enum weekday { sun, mon, tue, wed, thu, fri, sat };

在C中这样的写法和直接对里面的元素直接赋值除了语法上效果完全一样。但是在之后的许多语言中,枚举类型是一个真正的类型

还有一些语言中提供一种称为子界的类型,它表示一种基于基本数值的一个连续的区间。比如Pascal中表示1到100:

type test_score = 0..100

复合类型:由一些简单的基本类型组合成的一些类型称为复合类型,比如常见的记录、变体记录、数组、集合、指针、表等,具体的都会在后面详细介绍。

类型检查

大多数的静态类型语言中,定义一个对象都是需要描述清楚它的类型,进一步讲,这些对象出现的上下文也都是有类型的,也就是说语言中的一些规则限制了这种上下文中可以合法出现的对象类型。

类型相容确定了一个特定类型的对象的能否用在一个特定上下文中。在最极端的情况下,对象可使用的条件就是它的类型与上下文所期望的类型等价。但是在大多数语言中,相容关系都比等价更宽松一些,即使对象与上下文的类型不同,它们也可以相容。

而类型推理想回答的是从一个简单的表达式出发构造另一个表达式时,这整个的表达式的类型是什么

类型等价

在用户可以定义新类型的语言中,类型等价的定义一般基于两种形式。

type R2 = record a : integer b : integer end; type R2 = record b : integer a : integer end;

结构等价

基于类型定义的内容,就是它们由同样的组成部分且按照同样的方式组合而成

它的准确定义在不同的语言中也不一样,因为它们要决定类型之间的哪些潜在差异是重要的,哪些是可以接受的(比如上面的两个定义,是否还认为是等价的)。结构等价是一种很直接的认识类型的方式,早期的一些语言(Algol 68、Modula-3、ML)有些事基于结构等价的,现在的大部分语言(Java、C#)大都是基于名字等价了,为何呢?因为从某种意义上看,结构等价是由底层、由实现决定的,属于比较低级的思考方式。就如一个上下文,如果你传递了一个结构等价但是不是所期待对象,实施结构等价的编译器是不会拒绝这种情况的(假如这不是你希望的,那么你也不会得到任何提示或者错误信息,很难排查的)。

名字等价

基于类型的词法形式,可以认为是每一个名字都引进一个新的类型;

它基于一种假设,就是说程序员花时间定义了两个类型,虽然它们的组成部分可能相同,但是程序员要表达的意思就是这是两个不同的类型。名字等价的常规判断就非常简单了,看看声明两个对象的类型是否是一个就是了。但是也会有一些特殊的情况出现,比如类型别名(C、C++的程序员很熟悉这种东西吧),比如 typedef int Age; 就为int类型重新定义了一个别名"Age"。那些认为int不等价越Age的语言称为严格名字等价,认为等价的称为宽松名字等价。其实这两种也是很容易区分的,只要能区分声明和定义两个概念的差异就可以区分。在严格名字等价中看待typedef int Age是认为定义了一个新类型Age,在宽松名字等价看来这就是一个类型声明而已,int和Age共享同一个关于整数的定义。

类型变换和转换

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjysj.html