仓颉语言类型系统 Skill
- 类型系统概述
-
仓颉是静态类型语言,支持子类型多态
-
若参数/变量/返回类型为 T ,可接受 T 的任何子类型
-
仓颉不支持不同类型之间的隐式转换(子类型到父类型不被视为"转换")
- 子类型关系
2.1 子类型关系来源
-
类继承:class Sub <: Super {} → Sub <: Super
-
接口实现(含扩展实现):类型实现接口后成为接口的子类型
-
元组类型(协变,逐元素):(C2, C4) <: (C1, C3) 若 C2 <: C1 且 C4 <: C3
-
函数类型(参数逆变,返回协变):(U1) -> S2 <: (U2) -> S1 当且仅当 U2 <: U1 且 S2 <: S1
-
恒真关系:
-
T <: T (自反性)
-
Nothing <: T 对所有 T 成立
-
T <: Any 对所有 T 成立
-
C <: Object 对任何 class C 成立
-
传递性:若 A <: B 且 B <: C ,则 A <: C
2.2 泛型类型的子类型关系
-
根据泛型定义中的继承声明确定,如 class C<Z> <: I<Z, Z> {} → C<Bool> <: I<Bool, Bool>
-
用户定义的泛型类型在类型参数处默认不型变(详见下文型变规则)
- 型变规则(Variance)
3.1 定义
设 A 、B 为类型,T 为类型构造器(含一个类型参数 X ):
型变 条件 说明
不型变(invariant) T<A> <: T<B> 当且仅当 A = B
用户定义的泛型类型默认行为
协变(covariant) T<A> <: T<B> 当且仅当 A <: B
内建元组类型对每个元素协变
逆变(contravariant) T<A> <: T<B> 当且仅当 B <: A
内建函数类型在参数处逆变
3.2 仓颉中的规则
-
用户自定义泛型类型:在所有类型变元处不型变
-
例:给定 interface I<X> 和 D <: C ,I<D> <: I<C> 不成立
-
仅当 A = B 时,I<A> <: I<B> 才成立
-
内建元组类型:对每个元素类型协变
-
内建函数类型:入参类型处逆变,返回类型处协变
注意:class 以外的类型实现接口,该类型和该接口之间的子类型关系不能作为协变和逆变的依据。
- 类型转换
4.1 无隐式转换
-
仓颉无隐式类型转换(子类型到父类型不被视为"转换")
-
所有类型转换须显式进行
4.2 数值转换
-
T(e) 其中 T 和 e 为任意数值类型(Int8 /Int16 /Int32 /Int64 /IntNative /UInt8 /UInt16 /UInt32 /UInt64 /UIntNative /Float16 /Float32 /Float64 )
-
可能溢出:编译时检测 → 错误;运行时 → 异常
4.3 Rune ↔ 整数转换
-
UInt32(runeExpr) — 返回 Unicode 标量值
-
Rune(intExpr) — 仅当值在 [0x0000, 0xD7FF] 或 [0xE000, 0x10FFFF] 范围内有效;否则编译报错或运行时抛异常
4.4 is 运算符
- e is T → Bool 。当 e 的运行时类型是 T 的子类型时返回 true
let b: Base = Derived() b is Derived // true b is Base // true
4.5 as 运算符
-
e as T → Option<T> 。运行时类型是子类型时返回 Some(e) ,否则返回 None
-
安全向下转型机制 — 无异常,仅返回 Option
let b: Base = Derived() b as Derived // Option<Derived>.Some(b) b as String // Option<String>.None
- 类型别名
5.1 声明
-
关键字:type
-
语法:type Alias = OriginalType
-
不创建新类型 — 仅为替代名称
5.2 规则
-
仅限顶层 — 不能在函数内定义
-
原始类型须在别名定义处可见
-
不允许循环引用 — 直接或间接循环均禁止
5.3 使用场景
-
作为类型:var a: A = B() 其中 type A = B
-
作为构造函数(当别名指向 class/struct 时):A() 构造 B
-
访问静态成员:A.foo() 、A.b
-
访问枚举构造函数:Time.Day 其中 type Time = TimeUnit
5.4 限制
- 用户自定义类型别名不能用于类型转换表达式
5.5 泛型类型别名
-
类型别名可声明类型参数
-
不能对别名类型参数使用 where 约束
type RD<T> = RecordData<T>