.. _variants: ======= 变体 ======= 变体是无名类型,它们支持可以是许多命名 case 之一的值,每个 case 可能具有不同的值和类型:: var t : variant 有一个简写类型 alias 语法来定义 variant:: variant U_F { i_value : uint f_value : float } typedef U_F = variant // 与上述声明完全相同 如果任意两个变体具有相同类型的相同命名个案,则它们属于同一类型,并且顺序相同。 变体保存当前 case 的 ``index`` ,以及仅当前 case 的值。 当前的大小写选择可以通过 ``is`` 运算符检查,并通过 ``as`` 运算符访问:: assert(t is i_value) assert(t as i_value == 0x3f800000) 可以通过复制不同 case 的正确构造的变体来修改整个变体选择:: t = U_F(i_value = 0x40000000) // 现在是 i_value t = U_F(f_value = 1.0) // 现在是 f_value 访问类型不正确的 variant case 将导致 panic:: t = U_F(i_value = 0x40000000) return t as f_value // panic, 无效的变体索引 可通过``?as``作进行安全导航:: return t ?as f_value ?? 1.0 // 如果 t 不f_value,将返回 1.0 也可以以不安全的方式访问 Cases,而无需检查类型:: unsafe { t.i_value = 0x3f800000 return t.f_value // 将返回 f_value 占用的内存 - 即 1.0f } 当前索引可以通过 ``variant_index`` 函数来确定:: var t : U_F assert(variant_index(t)==0) 特定情况的索引值可以通过 ``variant_index`` 和 ``safe_variant_index`` 类型特征来确定。 对于无效的索引和类型,``safe_variant_index`` 将返回 -1,而 ``variant_index`` 将报告编译错误:: assert(typeinfo(variant_index t)==0) assert(typeinfo(variant_index t)==1) assert(typeinfo(variant_index t)==-1) // compilation error assert(typeinfo(safe_variant_index t)==0) assert(typeinfo(safe_variant_index t)==1) assert(typeinfo(safe_variant_index t)==-1) 当前 case 选择可以通过不安全作 ``safe_variant_index`` 来修改:: unsafe set_variant_index(t, typeinfo variant_index(t)) ------------------------- 对齐和数据布局 ------------------------- 变体包含当前 case 的“索引”,后跟各个 case 的并集,类似于以下 C++ 布局:: struct MyVariantName { int32_t __variant_index; union { type0 case0; type1 case1; ... }; }; 单个个案从相同的偏移量开始。 variant 类型通过其最大大小写的对齐方式进行对齐,但不小于 int32 的对齐方式。