02 Type System¶
YIAN 的类型系统包括以下几个大类
- 基本类型: 构成类型的基础, 包括算术类型等
- 派生类型: 由其他类型派生而来, 包括数组, 指针等
- 自定义类型: 用户定义的类型, 包括 struct, enum, trait, 函数类型等
- 泛型类型: 在泛型上下文中使用的类型, 本质上是类型占位符, 详见泛型章节
Basic Types¶
YIAN 支持以下基本类型:
void: 无类型, 用于表示没有值的情况, 不占用内存bool: 布尔类型, 只有两个值true和false, 占用 1 字节char: 字符类型, 用于表示单个 Unicode 字符, 占用 4 字节str: 字符串切片类型, 用于引用一个字符串, 占用 16 字节- 其中 8 字节用于存储指向字节序列的指针, 另 8 字节用于存储字符串总的字节数
i8,i16,i32,i64: 有符号整数类型, 分别占用 8, 16, 32, 64 位u8,u16,u32,u64: 无符号整数类型, 分别占用 8, 16, 32, 64 位f32,f64: 浮点数类型, 分别占用 32 和 64 位
Derived Types¶
派生类型是由其他任何类型派生而来的类型
数组类型¶
数组类型表示一个固定长度的序列, 元素类型相同, 语法为 <element_type>[<length>]
<element_type>: 数组中元素的类型<length>: 数组的长度, 必须是一个自然数常数(0也是合法的长度)- 数组所占用的内存大小等于元素类型的大小乘以数组长度
元组类型¶
元组类型表示一个固定长度的序列, 元素类型可以不同, 语法为 (<type1>, <type2>, ..., <typeN>)
<type1>, <type2>, ..., <typeN>: 元组中每个元素的类型- 元组所占用的内存大小不一定等于所有元素类型大小之和, 可能会有内存对齐的填充, 参考 C 语言中的结构体内存布局
指针类型¶
指针类型表示一个存储特定类型值的内存地址, 语法为 <pointee_type>*
<pointee_type>: 指针指向的值的类型- 指针类型占用 8 字节, 无论指向的类型是什么
切片类型¶
切片类型表示一个动态长度的序列, 元素类型相同, 语法为 <element_type>[]
<element_type>: 切片中元素的类型- 切片类型占用 16 字节, 其中 8 字节用于存储指向元素序列的指针, 另 8 字节用于存储切片的长度(元素个数)
函数指针类型¶
函数指针类型表示一个函数的内存地址, 语法为 fn<<return_type>(<param_type1>, <param_type2>, ..., <param_typeN>)>
<return_type>: 函数的返回类型<param_type1>, <param_type2>, ..., <param_typeN>: 函数的参数类型列表- 函数指针类型占用 8 字节, 存储函数的内存地址
Custom Types¶
用户可以自定义 struct, enum, trait, 函数, 方法, 这些类型被称为自定义类型, 它们:
Struct¶
struct 是一种复合类型, 用于将多个相关的值组合成一个单一的实体, 语法为:
<access_modifier> struct <struct_name><type_parameters> {
<access_modifier1> <field_type1> <field_name1>
<access_modifier2> <field_type2> <field_name2>
...
<access_modifierN> <field_typeN> <field_nameN>
}
<access_modifier>: 可选的访问修饰符<struct_name>: struct 的名字<type_parameters>: 可选的类型参数列表, 用于定义泛型 struct<field_type1> <field_name1>: struct 的字段, 包含字段类型和字段名字, 可以有访问修饰符- struct 的内存布局由其字段的类型和顺序决定, 可能会有内存对齐的填充, 参考 C 语言中的结构体内存布局
Enum¶
enum 是一种代数数据类型, 用于表示一个值可以是几种不同类型中的一种, 语法为:
<access_modifier> enum <enum_name><type_parameters> {
<variant_name1> {
<field_type1> <field_name1>
<field_type2> <field_name2>
...
<field_typeN> <field_nameN>
}
<variant_name2> {
...
}
...
<variant_nameM> {
...
}
}
<access_modifier>: 可选的访问修饰符<enum_name>: enum 的名字<type_parameters>: 可选的类型参数列表, 用于定义泛型 enum<variant_name1>: enum 的变体名字, 每个变体可以有自己的 payload, 包含字段类型和字段名字, 也可以没有 payload, 这时不需要花括号- enum 占用的内存分为两部分: discriminant 和 payload, discriminant 用于区分不同的变体, 占用 4 字节, payload 用于存储变体的字段, 占用所有变体中字段占用内存最大的那个的大小
Trait¶
trait 是一种抽象类型, 用于定义一组方法的签名, 类似于接口, 语法为:
<access_modifier> trait <trait_name><type_parameters> {
<method_declaration1>/<method_definition1>
<method_declaration2>/<method_definition2>
...
<method_declarationN>/<method_definitionN>
}
<access_modifier>: 可选的访问修饰符<trait_name>: trait 的名字<type_parameters>: 可选的类型参数列表, 用于定义泛型 trait<method_declaration>: 方法的声明, 格式与函数声明相同, 但使用分号;结尾, 而不是函数定义中的花括号{ ... }<method_definition>: 方法的定义, 格式与函数定义相同, 包含方法体, 用花括号{ ... }包围- 方法前面可以有访问修饰符
- 方法前面可以添加
static关键字, 使其成为一个静态方法 - trait 必须配合 impl 块使用, 详见方法章节
函数类型¶
每个函数都有自己独特的类型, 即使它们的参数和返回类型完全相同, 当定义一个函数时, 编译器会为它生成一个匿名的函数类型, 包含以下信息:
- 函数的名字
- 函数的访问修饰符
- 函数的类型参数列表(如果有的话)
- 函数的参数类型列表以及参数名
- 函数的返回类型
方法类型¶
每个方法也有自己独特的类型, 包含以下信息:
- 方法的名字
- 方法的访问修饰符
- 方法的类型参数列表(如果有的话)
- 方法的参数类型列表以及参数名
- 方法的返回类型
- 方法所属的类型
- 方法是否包含默认实现
Type Cast¶
YIAN 仅支持预先规定好的, 基本类型之间的类型转换, 规则为:
- 所有的算术类型(整数类型和浮点数类型)之间都可以相互转换
char类型可以转换为任何整数类型- 不超过 4 字节的无符号整数类型可以转换为
char类型
YIAN不存在隐式的类型转换, 以上的类型转换都必须使用显式的类型转换语法, 详见语句章节
如果用户需要自定义类型转换, 可以通过实现标准库中的 From, Into trait 来实现, 详见标准库章节