概念
- 一个数据类型 data type 指的是 一些数据对象的集合以及它们拥有的操作
- 描述符 descriptor 是一个变量的属性的集合,主要用于类型检查和内存分配操作。如果属性都是静态的,那么描述符只需要存在于编译时,如果有属性是动态的,则运行时系统需要负责维持描述符。
- 对于数据类型的设计,最重要的一点是——该数据类型有什么操作,这些操作的定义是什么。
基础数据类型(Primitive Data Types)
- 大部分语言都预设了基础数据类型,有一些完全是硬件层面的映射(比如 byte),有一些通过在硬件层面做出小小的努力就能实现(比如 float)
- 整数类型 integer,如 byte, short, int, long
- 浮点数, 近似地模拟实数。
常见的底层实现 - 复数(Complex) 少数语言将复数也作为基本数据类型
- 小数(Decimal) 主要用于商业应用,要求数据精确,但是取值范围有限且浪费内存
- 布尔值(Boolean) 最简单的数据类型(甚至可以用一个bit实现),优点是增强可读性
- 字符(Character) 以数字的形式储存,需要指定解码标准(比如 ASCII)
字符串类型(Character String Types )
- 有的语言将字符串作为基本数据类型,有的则用字符的数组表示(比如 C)
- 字符串的长度应该是动态的还是静态的?(Java等选择静态,python JavaScript等选择动态,C/C++则是有限制的动态,因为数组长度确定,以\0为结尾标记)
- 常见操作有 Assignment and copying 赋值与复制,Comparison (=, >, etc.) 比较,Catenation 连接,Substring reference 取子串,Pattern matching 模式匹配
- 浅析实现方法
- 对于静态字符串,只需要创建编译时的描述符
- 对于有限制的动态字符串,则_可能_需要维持一个运行时的描述符来标记最大长度和当前长度
- 对于完全动态的字符串实现,则一定要维持一个运行时的描述符,且最大的实现难点在于内存的分配和释放
- 对于静态字符串,只需要创建编译时的描述符
- 实现字符串数据类型的意义:增强表达性(writability),因为这个数据类型非常常用
枚举类型(Enumeration Types)
- 概念就不说了
- 设计实现的一些考虑:
- 一个枚举常量允许出现在一个以上的枚举类型定义里吗?如果可以,怎么区分(类型检查)?
- 枚举类型的值可以和整数类型相互转换吗?
- 枚举类型的值可以和其他类型相互转换吗?
- 枚举类型的意义:
- 增强了可读性 (例:用RED 表示 红色,而不是用 1 表示红色)
- 增强了稳定性,编译器可以对枚举类型变量进行类型检查
子范围类型(Subrange Types)
- 子范围类型的变量可取值是某种数据类型的一部分连续子序列 比如 定义 12~18 是青少年年龄数据类型
- 子范围类型的意义:
- 增强了可读性
- 增强了稳定性,可取值范围外的值都会被编译器当做错误
数组类型(Array Types)
- 数组的元素必须是同类的,元素靠的是相对于第一个元素的位置进行定位
- 数组内存分配与下标范围(subscript ranges )的几种不同实现:
- 静态(static): 下标范围和内存分配都在程序运行前就确定了。 优点是高效,因为不需要动态的分配和释放内存。
- 固定栈动态(Fixed stack-dynamic):下标范围是静态的,但是内存分配是在声明时完成的(运行时在栈中分配之后就固定了)。 优点是节约空间,多个数组可以共享一片内存(只要它们不同时active);缺点是需要动态的分配与释放内存,降低了运行效率。
- 固定堆动态(Fixed heap-dynamic) 类似于固定栈动态,只是内存是从堆中分配。
- 堆动态(Heap-dynamic)下标范围和内存分配都是动态的(在栈中)。优点是灵活,数组的长度和空间可以在运行时随意改变。缺点是效率较低。
- 异类数组(Heterogeneous Arrays) 允许同时存在不同类型元素,通常出现在动态类型语言中如 Perl, Python, JavaScript, and Ruby
###待续