类型关系
以下部分定义描述了编译器完成类型检查所需要的几种类型关系。
类型相等性
Nim 对大多数类型使用结构类型相等。仅对对象、枚举和 distinct 类型以及泛型类型使用名称相等。
Subtype关系
如果对象 a 继承自 b , a 将是 b 的子类型。
子类型关系被延伸到类型 var , ref , prt 。如果 A 是 B 的子类型, A 和 B 是 object 类型那么:
- var A是var B的子类型
- ref A是ref B的子类型
- ptr A是ptr B的子类型。
注意: 从子类型到父类型的赋值,需要上述指针注解之一,以防止 “对象切割” 。
转换关系
如果以下算法返回 true,则类型 a 隐式 可转换为类型 b :
proc isImplicitlyConvertible(a, b: PType): bool =
if isSubtype(a, b):
return true
if isIntLiteral(a):
return b in {int8, int16, int32, int64, int, uint, uint8, uint16,
uint32, uint64, float32, float64}
case a.kind
of int: result = b in {int32, int64}
of int8: result = b in {int16, int32, int64, int}
of int16: result = b in {int32, int64, int}
of int32: result = b in {int64, int}
of uint: result = b in {uint32, uint64}
of uint8: result = b in {uint16, uint32, uint64}
of uint16: result = b in {uint32, uint64}
of uint32: result = b in {uint64}
of float32: result = b in {float64}
of float64: result = b in {float32}
of seq:
result = b == openArray and typeEquals(a.baseType, b.baseType)
of array:
result = b == openArray and typeEquals(a.baseType, b.baseType)
if a.baseType == char and a.indexType.rangeA == 0:
result = b == cstring
of cstring, ptr:
result = b == pointer
of string:
result = b == cstring
of proc:
result = typeEquals(a, b) or compatibleParametersAndEffects(a, b)
我们使用判断 typeEquals(a, b) 表示 “类型相等” 属性,使用判断 isSubtype(a, b) 表示 “子类型关系”。compatibleParametersAndEffects(a, b) 当前未指定。
Nim 的 range 类型构造器也执行隐式转换。
让 a0, b0 为类型 T 。
让 A = range[a0..b0] 为实参类型, F 为形参类型。如果 a0 >= low(F) and b0 <= high(F) 并且 T 和 F 都是有符号整数或两者都是无符号整数,则存在从 A 到 F 隐式转换。
如果下列算法返回 true,则类型 a 是显示转换为类型 b :
proc isIntegralType(t: PType): bool =
result = isOrdinal(t) or t.kind in {float, float32, float64}
proc isExplicitlyConvertible(a, b: PType): bool =
result = false
if isImplicitlyConvertible(a, b): return true
if typeEquals(a, b): return true
if a == distinct and typeEquals(a.baseType, b): return true
if b == distinct and typeEquals(b.baseType, a): return true
if isIntegralType(a) and isIntegralType(b): return true
if isSubtype(a, b) or isSubtype(b, a): return true
可转换关系可以通过用户定义的类型 converter “转换器”放宽。
converter toInt(x: char): int = result = ord(x)
var
x: int
chr: char = 'a'
# 这里产生隐式转换
x = chr
echo x # => 97
# 也可以使用显式形式
x = chr.toInt
echo x # => 97
如果 a 是左值,并且 typeEqualsOrDistinct(T, typeof(a)) 成立,则类型转换 T(a) 是左值。
赋值兼容
一个表达式 b 可以被赋值给一个表达式 a 如果 a 是一个 l-value 并且保持 isImplicitlyConvertible(b.typ, a.typ) 。