数据类型

在计算机科学和计算机编程中,数据类型(或简单类型)是数据值的集合或分组,通常由一组可能的值,一组允许对这些值的操作和/或这些值表示这些值作为机器类型。程序中的数据类型规范会限制表达式可能采用的表达式(例如变量或函数调用)的可能值。在文字数据上,它告诉编译器或解释器程序员打算如何使用数据。大多数编程语言都支持整数的基本数据类型(不同尺寸),浮点数(近似实数),字符和布尔值。
概念
可以为许多原因指定数据类型:相似性,便利性或集中注意力。良好的组织通常是一个有助于理解复杂定义的问题。几乎所有编程语言都明确包括数据类型的概念,尽管可能的数据类型通常受到简单性,可计算性或规律性的考虑。明确的数据类型声明通常允许编译器选择有效的机器表示形式,但是数据类型提供的概念组织不应折现。
不同的语言可能使用不同语义的不同数据类型或类似类型。例如,用Python编程语言,int
代表一个任意的精确整数,该整数具有传统的数字操作,例如加法,减法和乘法。但是,用Java编程语言,类型int
代表一个32位整数的集合,价值从-2,147,483,648到2,147,483,647,其算术操作包裹在溢出上。在Rust中,这种32位整数类型表示i32
以及在调试模式下溢出的恐慌。
大多数编程语言还允许程序员定义其他数据类型,通常通过组合其他类型的多个元素并定义新数据类型的有效操作。例如,程序员可能会创建一个名为“复杂号码”的新数据类型,该数据类型包括真实和虚构的零件,或者由三个字节表示的颜色数据类型表示,表示红色,绿色和蓝色的每个字符,以及代表代表该字符串的字符串颜色的名称。
数据类型在类型系统中使用,这些系统提供了各种定义,实现和使用它们的方式。在类型系统中,数据类型表示对数据解释的约束,描述了存储在计算机内存中的值或对象的表示,解释和结构。该类型系统使用数据类型信息来检查访问或操纵数据的计算机程序的正确性。编译器可以使用值的静态类型来优化其所需的存储,并选择用于该值操作的算法。在许多C编译器中float
例如,数据类型以32位表示,符合单精度浮点数的IEEE规范。因此,他们将对这些值(浮点添加,乘法等)使用浮点特异性的微处理器操作。
统计数据中的大多数数据类型在计算机编程中具有可比的类型,反之亦然,如下表所示:
统计数据 | 程式设计 |
---|---|
实用值(间隔尺度) | 浮点 |
真实价值(比例) | |
计数数据(通常非负) | 整数 |
二进制数据 | 布尔 |
分类数据 | 枚举类型 |
随机向量 | 列表或数组 |
随机矩阵 | 二维阵列 |
随机树 | 树 |
定义
Parnas,Shore&Weiss(1976)确定了在文献中使用的“类型”的五个定义:
- 句法
- 一种类型是声明变量关联的纯句法标签。尽管对于高级类型系统(例如子结构类型系统) ,但此类定义没有提供类型的直观含义。
- 表示
- 一种类型是根据更原始类型(通常是机器类型的组成)定义的。
- 表示和行为
- 一种类型被定义为其表示形式和一组操作人员来操纵这些表示形式。
- 价值空间
- 一种类型是变量可以拥有的一组可能的值。这样的定义使谈论(不相关)工会或笛卡尔类型的产品成为可能。
- 价值空间和行为
- 一种类型是一组变量可以拥有的值,也是可以应用于这些值的一组函数。
在表示形式方面的定义通常是用诸如Algol和Pascal的命令式语言完成的,而价值空间和行为的定义是在诸如Simula和Clu之类的高级语言中使用的。包括行为在内的类型与面向对象的模型更紧密地对齐,而结构化编程模型往往不包括代码,被称为普通的旧数据结构。
分类
数据类型可以根据几个因素进行分类:
- 原始数据类型或内置数据类型是内置于语言实现的类型。用户定义的数据类型是非重要性类型。例如,Java的数字类型是原始的,而类是用户定义的。
- 原子类型的值是一个单个数据项,无法分解为组件部分。复合类型或聚合类型的值是可以单独访问的数据项的集合。例如,尽管它由一系列位组成,而整数肯定是复合的,但整数通常被视为原子。
- 基本数据类型或基本数据类型是根据基本概念或列举其元素来定义的。根据其他数据类型指定并部分定义生成的数据类型或派生数据类型。所有基本类型都是原子。例如,整数是数学定义的基本类型,而整数数组是将数组类型生成器应用于整数类型的结果。
术语各不相同 - 在文献中,可以互换使用原始,内置,基本,原子和基本。
例子
机器数据类型
基于数字电子设备的计算机中的所有数据均以最低级别表示为位(替代方案0和1)。最小的可寻址数据单位通常是一组称为字节的位(通常为8位八位字)。通过机器代码指令处理的单元称为单词(截至2011年,通常为32或64位)。
机器数据类型会暴露或提供对硬件的细粒度控制,但这还可以揭示实现详细信息,从而使代码较低。因此,机器类型主要用于系统编程或低级编程语言。在高级语言中,大多数数据类型都被抽像出来,因为它们没有语言定义的机器表示。例如, C编程语言提供类型,例如布尔值,整数,浮点数等,但是这些类型的精确位表示是实现的。唯一具有精确计算机表示的C类型是char
代表字节的类型。
布尔类型
布尔类型代表值真实和错误。尽管只有两个值是可能的,但它们通常以单词的形式表示,因为它需要更多的机器说明来存储和检索个人位。许多编程语言没有明确的布尔类型,而是使用整数类型和解释(例如)为false,而其他值则为true。布尔数据是指语言如何解释给机器语言的逻辑结构。在这种情况下,布尔值0指的是逻辑false。 true始终是非零的,尤其是一个被称为布尔1的零。
数字类型
几乎所有编程语言都提供一种或多种整数数据类型。他们可以提供少量的预定义亚型,仅限于某些范围(例如short
和long
和他们的对应unsigned
C/C ++中的变体;或允许用户自由定义子弹,例如1..12(例如pascal / ada )。如果目标平台上不存在相应的本机类型,则编译器将使用确实存在的类型将它们分解为代码。例如,如果在16位平台上请求32位整数,则编译器将默认地将其视为两个16位整数的数组。
浮点数据类型代表某些分数值(数学上的理性数字)。尽管它们在最大值和精度上都具有预定的限制,但有时它们被误导地称为真实物质(数学实数的回忆)。它们通常在内部以A×2 B ( A和B为整数)形式存储,但以熟悉的小数形式显示。
固定点数据类型方便表示货币价值。它们通常在内部作为整数实现,从而导致预定义的限制。
为了独立于建筑细节, bignum或任意精度numeric
可能会提供类型。这代表了仅由系统上的可用内存和计算资源限制的精度的整数或合理性。算术操作对机器大小值的算术实现比相应的机器操作明显慢得多。
枚举
枚举类型具有不同的值,可以进行比较和分配,但不一定在计算机的内存中具有任何特定的具体表示。编译器和口译员可以任意表示它们。例如,扑克牌甲板上的四个西服可能是四个枚举者,名为Club , Diamond , Heart , Spade ,属于枚举类型的名为西装。如果将变量V声明为诉讼为其数据类型,则可以为其分配这四个值中的任何一个。某些实现使程序员可以将整数值分配给枚举值,甚至可以将它们视为与整数类型相等的。
字符串和文字类型
字符串是用于存储单词或纯文本的字符序列,大多数经常代表格式的文本文字标记语言。字符可能是某些字母,数字,空白空间,标点符号等的字母。字符是从诸如ASCII之类的字符集中绘制的。字符和字符串类型可以根据字符编码具有不同的子类型。最初的7位宽ASCII被发现受到限制,并由8、16和32位的套装取代,它们可以编码各种非拉丁语字母(例如希伯来语和中文)和其他符号。字符串可能具有可变长度或固定长度,并且某些编程语言具有两种类型。它们的最大尺寸也可能是亚型的。
由于大多数字符集都包含数字,因此可以具有数字字符串,例如"1234"
。这些数字字符串通常被认为与数字值不同,例如1234
,尽管某些语言在它们之间自动转换。
工会类型
联合类型定义将指定哪些允许的子类型中的哪个可以存储在其实例中,例如“ float或long Anteger”。与可以定义为包含浮子和整数的记录相反,一个联合可能一次只包含一个亚型。
标记的联盟(也称为变体,变体记录,歧视联合或不相交联合)包含一个额外的字段,指示其当前类型以增强类型的安全性。
代数数据类型
代数数据类型(ADT)可能是产品类型的递归总和类型。 ADT的值由一个构造函数标签组成,其字段值或多个字段值,以及由构造函数固定的字段值的数字和类型。 ADT的所有可能值集的集合是其变体的所有可能值集的集合理论分离结合(SUM)(字段的乘积)。用模式匹配分析代数类型的值,该模式匹配标识值的构造函数并提取其包含的字段。
如果只有一个构造函数,则ADT对应于类似于元组或记录的产品类型。没有字段的构造函数对应于空产品(单位类型)。如果所有构造函数都没有字段,则ADT对应于枚举类型。
一个常见的ADT是选项类型,在Haskell中定义为data Maybe a = Nothing | Just a
.
数据结构
某些类型对于存储和检索数据非常有用,被称为数据结构。常见数据结构包括:
- 数组(也称为向量,列表或序列)存储许多元素,并随机访问单个元素。数组的元素通常(但在所有情况下)都是相同类型所需的。阵列可以是固定长度或可扩展的。通常需要将索引成整数(如果不是的话,可能会通过谈论关联阵列)从特定范围(如果不是该范围的所有索引对应于元素,可能是一个稀疏的数组)。
- 记录(也称为元组或结构)记录是最简单的数据结构之一。记录是一个包含其他值的值,通常以固定数字和序列,通常由名称索引。记录的元素通常称为字段或成员。
- 一个对象包含许多数据字段,例如记录,还提供了许多用于访问或修改它们的子例程,称为方法。
- 单链接列表,可用于实现队列并在Haskell中定义为ADT
data List a = Nil | Cons a (List a)
, 和 - 二进制树,允许快速搜索,可以在Haskell中定义为ADT
data BTree a = Nil | Node (BTree a) a (BTree a)
抽像数据类型
抽像数据类型是一种数据类型,未指定数据的具体表示。取而代之的是,基于数据类型的操作的形式规范用于描述它。规范的任何实施都必须符合给出的规则。例如,堆栈具有遵循终点性规则的推/弹出操作,并且可以使用列表或数组来具体实现。抽象的数据类型用于正式语义和程序验证中,并且不太严格地在设计中使用。
指针和参考
主要的非复合类型类型是指针,一种数据类型,其值直接指(或“指向”)使用其地址在计算机内存中其他位置存储的另一个值。这是一种原始的参考。 (用日常术语来说,一本书中的页码可以被视为指另一个数据)。指针通常以类似于整数的格式存储;但是,试图取消或“查找”一个指针,其价值从来没有有效的内存地址会导致程序崩溃。为了改善这一潜在问题,即使基础表示形式相同,指针也被认为是它们指向的数据类型的单独类型。
功能类型
功能编程语言将函数视为独特的数据类型,允许此类型的值存储在变量中并传递给函数。一些多范式语言(例如JavaScript)也具有将功能视为数据的机制。大多数当代类型系统都超出了JavaScript的简单类型的“功能对象”,并具有由参数和返回类型区分的功能类型,例如类型Int -> Bool
表示功能采用整数并返回布尔值。在C中,一个函数不是一流的数据类型,而是可以通过程序来操纵功能指针。 Java和C ++最初没有功能值,但已在C ++ 11和Java 8中添加它们。
类型构造函数
一种类型的构造函数从旧类型中构建新类型,可以将其视为操作员以零或更多类型作为参数并产生类型的操作员。可以将产品类型,功能类型,功率类型和列表类型制成类型的构造函数。
量化类型
普遍定量和存在的类型基于谓词逻辑。通用量化被编写为或forall x. f x
并且是所有类型的交叉点x
身体f x
,即价值是类型的f x
每个x
。存在为或以或exists x. f x
并且是所有类型的联盟x
身体f x
,即价值是类型的f x
对于一些x
.
在Haskell中,普遍使用通用量化,但是必须通过转换来编码存在类型exists a. f a
到forall r. (forall a. f a -> r) -> r
或类似类型。
改进类型
改进类型是一种具有谓词的类型,该类型假定为精制类型的任何元素保留。例如,自然数的类型大于5,可以写为
相关类型
依赖类型是一种类型,其定义取决于值。依赖类型的两个常见示例是依赖函数和依赖对。依赖函数的返回类型可能取决于其参数之一的值(不仅仅是类型)。依赖对可能具有第二个值,该值取决于第一个值。
相交类型
相交类型是一种包含两个指定类型中成员的值的类型。例如,在Java班上Boolean
同时实现Serializable
和Comparable
接口。因此,类型的对象Boolean
是类型的成员Serializable & Comparable
。将类型视为一组值,相交类型是和和。也可以定义相关的相交类型,该类型可能取决于术语变量。
元类型
一些编程语言表示类型信息作为数据,启用类型的内省和反思。相比之下,高阶类型系统,同时允许从其他类型构造类型并将功能传递给值,通常避免在其上基于计算决策。
便利类型
为了方便起见,高级语言和数据库可以提供现成的“现实世界”数据类型,例如时间,日期和货币价值(货币)。这些可能是内置的语言,也可以作为库中的复合类型实现。