Skip to content

02 Type System

YIAN 的类型系统包括以下几个大类

  1. 基本类型: 构成类型的基础, 包括算术类型等
  2. 派生类型: 由其他类型派生而来, 包括数组, 指针等
  3. 自定义类型: 用户定义的类型, 包括 struct, enum, trait, 函数类型等
  4. 泛型类型: 在泛型上下文中使用的类型, 本质上是类型占位符, 详见泛型章节

Basic Types

YIAN 支持以下基本类型:

  • void: 无类型, 用于表示没有值的情况, 不占用内存
  • bool: 布尔类型, 只有两个值 truefalse, 占用 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, 函数, 方法, 这些类型被称为自定义类型, 它们:

  • 有一个用户定义的名字, 必须是合法的标识符
  • 可以定义并包含类型参数, 使其成为泛型类型, 详见泛型章节
  • 可以定义访问修饰符, 例如 pub, 详见模块章节

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 来实现, 详见标准库章节