跳到主要内容
版本:master

类型

类型是表达式的属性,在 GS 中,表达式的类型体现在编译期和运行时。

分类

在 GS 中,类型根据其行为特性被分为以下大类;

  • 基础普通类型 (int, float 等)

    基础普通类型是最简单的类型,它们通常被用于表示一个有限的数值。这些类型的值占据的空间固定。

    在后续的文档中,提到的 基本类型数值类型 指代此类型。

  • 引用容器类型 (buffer, array, map, function 等)

    引用容器通常用于容纳其他的值,它们的容量不固定,这些类型受到垃圾回收(GC)的管理。这些类型的实例被 区分为 readonly, parallel 或 readwrite

  • 句柄类型 (handle)

    句柄类型是一种特殊的引用类型,它们不受跨域传递的限制——通常句柄会有自己的线程安全机制。


在后续的文档中,提到的 引用类型 可以指代 引用容器类型句柄类型

另外,文档中提到的 类型 这一概念,如果没有特别说明,都指的是运行时的实际类型——主要指的是被标注 为 mixed 的变量,或者被储存在其他容器中的值,这些值在编译期没有确定的类型,但在运行时,GS 会 为这些值提供运行时类型标注。

类型转换规则

GS 中,不同类型的值之间可以进行转换。

类型转换分为两种情况:

  • 类型转换,将值转变为没有类型从属关系的另一个值,例如,从整数类型转换到浮点数类型。
  • 类型断言,值实例本身确实就是目标类型,在编译时明确这个值的类型,例如,从 mixed 转换为 int

类型关系

在显式或隐式类型转换时,类型转换的规则略有不同,我们通过以下关系来表示类型之间的转换行为:

标识描述
🔄执行类型转换
🔍执行类型断言
不接受转换
✔️接收,直接赋值

需要说明的是,接下来介绍的类型转换仅考虑运行时类型,即如同从 mixed 变量转换到指定类型的情况。编译期可能会阻止下表中的部分类型转换 (例如尝试从字符串转换到枚举类型),但这些转换可以在运行时发生。

对于值类型与目标类型相同的情况,始终为 ✔️(显示类型转换时,raw_pointer 类型作为特例 ❌),其他类型(在运行时)转换关系如下表所示:

显式类型转换

因为目前 GS 的语法不允许显式类型转换到 ffi-struct 类型和委托类型,表中不列出这两列

| 值(运行时)类型\转换的目标类型 | int | bool | (其他非bool的)枚举类型 | float | raw_pointer | string | buffer | function | array | map | class_map | (其他)具体类类型 | handle | (其他)handle 类型 | | ----------------------------- | --- | ---- | ----------------------- | ----- | ------ ---- | ------ | ------ | -------- | ----- | --- | --------- | ----------------- | ------ | --------------------- | | nil | 🔄 | 🔄 | 🔄 | 🔄 | ❌ | 🔄 | 🔄 | ❌ | 🔄 | 🔄 | ✔️ | ✔️ | ✔️ | ✔️ | | void | 🔄 | 🔄 | 🔄 | ❌ | ❌ | 🔄 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | int | ✔️ | 🔄 | 🔄 | 🔄 | ❌ | 🔄 | 🔄 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | bool | 🔄 | ✔️ | 🔄 | 🔄 | ❌ | 🔄 | 🔄 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | (非bool的)枚举类型 | 🔄 | 🔄 | 🔄 | 🔄 | ❌ | 🔄 | 🔄 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | float | 🔄 | 🔄 | 🔄 | ✔️ | ❌ | 🔄 | 🔄 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | raw_pointer | ❌ | 🔄1 | ❌ | ❌ | ❌ | 🔄 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | ffi 结构体类型 | ❌ | 🔄1 | ❌ | ❌ | ❌ | 🔄 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | string | 🔄 | 🔄 | 🔄 | 🔄 | ❌ | ✔️ | 🔄 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | buffer | 🔄 | 🔄 | ❌ | 🔄 | ❌ | 🔄 | ✔️ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | function | ❌ | 🔄 | ❌ | ❌ | ❌ | 🔄 | ❌ | ✔️ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | 委托类型 | ❌ | 🔄 | ❌ | ❌ | ❌ | 🔄 | ❌ | ✔️ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | array | ❌ | 🔄 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔️ | ❌ | ❌ | ❌ | ❌ | ❌ | | map | ❌ | 🔄 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔️ | ❌ | ❌ | ❌ | ❌ | | class 实例 | ❌ | 🔄 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔️ | ✔️ | 🔍 | ❌ | ❌ | | handle 实例 | ❌ | 🔄 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔️ | 🔍 |


注释:

  1. 在 JIT 下,raw_pointer 可以转换到 bool 类型,转换规则为非零地址转换为 true,零地址转换为 false。
隐式类型转换

| 值(运行时)类型\转换的目标类型 | int | bool1 | (其他非bool的)枚举类型 | float | raw_pointer | (其他)ffi 结构体类型 | string | buffer | function | 委托类型 | array | map | class_map | (其他)具体类类型 | handle | (其他)handle 类型 | | ----------------------------- | --- | ---------------- | ----------------------- | ----- | ------ ---- | -------------------- | ------ | ------ | -------- | ------- | ----- | --- | --------- | ----------------- | ------ | --------------------- | | nil | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | | void | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | int | ✔️ | ❌ | ❌ | 🔄 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | bool | 🔄 | ✔️ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | (非bool的)枚举类型 | 🔄 | ❌ | 🔍 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | float | ❌ | ❌ | ❌ | ✔️ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | raw_pointer | ❌ | ❌ | ❌ | ❌ | ✔️ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | ffi 结构体类型 | ❌ | ❌ | ❌ | ❌ | 🔄 | 🔍 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | string | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔️ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | buffer | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔️ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | function | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔️ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | 委托类型 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔️ | 🔍 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | array | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔️ | ❌ | ❌ | ❌ | ❌ | ❌ | | map | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔️ | ❌ | ❌ | ❌ | ❌ | | class 实例 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔️ | ✔️ | 🔍 | ❌ | ❌ | | handle 实例 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔️ | 🔍 |


注释:

  1. 如果表达式作为 逻辑运算ifforwhile条件表达式 等语句的 条件语句 使用,而期待被转换为 bool 类型时,遵照各个类型 被作为条件时 的转换规则,见下表

具体的类型转换行为

以下是各个类型被执行类型转换或类型诊断时,将会遵照的具体行为:

nil
  • 显式转换int: 视为 0
  • 显式转换bool/ 作为条件时: 视为 false
  • 显式转换其他枚举类型: 视为对应枚举类型的 0 值对应的枚举项,如同将 0 转换到该枚举类型时的结果
  • 显式转换float: 视为 0.0
  • 显式转换string: 视为 "nil"
  • 显式转换buffer: 得到一个空的 buffer 实例
  • 显式转换array: 得到一个空的 array 实例
  • 显式转换map: 得到一个空的 map 实例
void
  • 显示转换int: 视为 0
  • 显式转换bool/ 作为条件时: 视为 false
  • 显式转换其他枚举类型: 视为对应枚举类型的 0 值对应的枚举项,如同将 0 转换到该枚举类型时的结果
  • 显式转换string: 视为 "void"
int
  • 显式转换bool/ 作为条件时: 如果值为 0,视为 false,否则视为 true
  • 显式/隐式转换float: 转换为对应的浮点数值
  • 显式转换其他枚举类型: 视为对应枚举类型中与该整数值对应的枚举项,对于不存在的枚举项,转换仍然成功。
  • 显式转换string: 转换为对应的字符串表示形式
  • 显式转换buffer: 以小端序,获取数值对应的 8 个字节填充的 buffer
bool
  • 显式转换int: 如果值为 true,视为 1,否则视为 0
  • 显式转换其他枚举类型: 如同先将值转换到 int,然后再转换到对应枚举类型
  • 显式转换float: 如果值为 true,视为 1.0,否则视为 0.0
  • 显式转换string: 如果值为 true,视为 "true",否则视为 "false"
  • 显式转换buffer: 如同先将值转换到 int,然后再转换到 buffer
(非 bool 的)枚举类型
  • 显式/隐式转换int: 得到当前枚举值储存的整数值
  • 显示转换到bool/ 作为条件时: 如果枚举值储存的整数值为 0,视为 false,否则视为 true
  • 显式转换其他枚举类型: 如同先将值转换到 int,然后再转换到对应枚举类型
  • 显式转换float: 如同先将值转换到 int,然后再转换为 float
  • 显式转换string: 转换为当前储存的整数值,对应到枚举的枚举项的名称。如果没有对应的枚举项,得到 "Invalid Enum(枚举类型名.整数值)"
  • 显式转换buffer: 如同先将值转换到 int,然后再转换到 buffer
float
  • 显式转换int: 取整为对应的整数值(向零取整)
  • 显式转换bool/ 作为条件时: 如果值严格为 0.0 ,视为 false,否则视为 true
  • 显式转换其他枚举类型: 如同先将值转换到 int,然后再转换到对应枚举类型
  • 显式转换string: 转换为对应的字符串表示形式
  • 显式转换buffer: 以大端序,获取浮点数值对应的 8 个字节填充的 buffer
raw_pointer
  • 显式转换string: 获取一段表示地址值的描述信息
  • 作为条件时: 如果地址值为 0,视为 false,否则视为 true
ffi 结构体类型
  • 显式转换string: 获取一段包含类型名称和地址的描述信息
  • 作为条件时: 如果地址值为 0,视为 false,否则视为 true
string
  • 显式转换int: 尝试将字符串视为十进制表示的整数字面量,跳过字符串开头的空白字符,不断读取直到遇到非十进制数字字符或字符串尾, 将该数值的字面量尝试转换为整数值(如果字面量过大可能发生溢出),数值开头可以包含一个 +- 表示字面量的符号,如果没有读取到任何数字字符,则为 0
  • 显式转换real: 尝试将字符串视为十进制表示的浮点数字面量,跳过字符串开头的空白字符,不断读取直到遇到非浮点数字字符,第二个小 数点或字符串尾,将该数值的字面量尝试转换为整数值(如果字面量过大可能发生溢出)将该数值的字面量尝试转换为整数值(如果字面量过大可能发生溢出),如果没有读 取到任何数字字符,则为 0,如果没有读取到任何数字字符,则为 0.0
  • 显式转换bool/ 作为条件时:视为 true
  • 显式转换其他枚举类型: 如同先将值转换到 int,然后再转换到对应枚举类型。
  • 显式转换buffer: 以字符串内容填充,得到一个 buffer,包含与源字符串相同的字节内容。
buffer
  • 显式转换int: 将 buffer 的前 8 个字节视为小端序的 64 位整数,如果 buffer 长度不足 8 字节,则高位补零
  • 显式转换float: 将 buffer 的前 8 个字节视为大端序的 64 位浮点数,如果 buffer 长度不足 8 字节,则高位补零
  • 显式转换bool/ 作为条件时: 视为 true
  • 显式转换其他枚举类型: 如同先将值转换到 int,然后再转换到对应枚举类型
  • 显式转换string: 将 buffer 中的字节内容填充得到一个 string,包含与源 buffer 相同的字节内容。
function
  • 显式转换string: 获取函数的名称或匿名函数的描述信息
  • 显式转换bool/ 作为条件时: 始终视为 true
委托类型
  • 显式转换string: 获取委托的目标函数名称或匿名函数的描述信息
  • 显式转换bool/ 作为条件时: 始终视为 true
array
  • 显式转换bool/ 作为条件时: 始终视为 true
map
  • 显式转换bool/ 作为条件时: 始终视为 true
class 实例
  • 显式转换bool/ 作为条件时: 始终视为 true
handle 实例
  • 显式转换string: 获取句柄类型名和实例标识的描述信息
  • 显式转换其他handle类型: 如果对象是目标句柄类型或其子类,则进行类型断言
  • 显式转换bool/ 作为条件时: 如果 handle 已经被关闭,视为 false,否则视为 true