Skip to Content

元组(Tuple)

元组是定长、异构、不可变的值序列。字面量与类型同形:(3, "甲") 的类型就是 (int, string),分量个数与每个分量的类型都是类型的一部分,(int, string) 与 (int, int)、(int, string, int) 互为不同类型。

字面量与类型

func main() -> int { val t = (3, "甲"); print(t, t is int); val u: (int, string, float) = (1, "乙", 2.5); print(u.Item0, u.Item1, u.Item2); val nest = ((1, 2), "x"); print(nest.Item0.Item1, nest); val p = (1); print(p, p is int); return 0; }
(3, 甲) False 1 乙 2.5 2 ((1, 2), x) 1 True
  • 至少两个分量才成元组:(1) 是带括号的表达式,类型还是 int。
  • 嵌套合法,外层分量自身还是元组,逐层 .Item 下钻。
  • 打印形如 (3, 甲),字符串分量不带引号。

位置成员:Item0 起

分量用 0 基的位置成员访问,t.Item0 是第一个分量。分量只读,元组是不可变值。

分量个数写在类型里,越界与异名成员都在编译期报错,不会等到运行期:

func main() -> int { val t = (3, "甲"); print(t.Item0, t.Item1); return 0; }
3 甲
error MS3281: Tuple '(int32, string)' has no component 'Item2': components are read-only .Item0 .. .Item1 (0-based).

下标读 t[0] 与 .Item0 等价,仅收界内常量整数,动态表达式、越界与多参下标会直接报错:

func main() -> int { val w: (int, string) = (3, "c"); print(w[0], w[1]); return 0; }
3 c

解构与多返回值

val / var 的声明位支持元组解构,一次命名多个分量。var 解构出的分量可以再赋值。

func DivMod(a: int, b: int) -> (int, int) { return (a / b, a % b); } func Sum(p: (int, int)) -> int { return p.Item0 + p.Item1; } func main() -> int { val (q, r) = DivMod(17, 5); print(q, r); print(Sum((3, 4))); var (a, b) = (1, 2); a = 9; print(a, b); return 0; }
3 2 7 9 2

函数返回元组是多返回值的常规形态,调用点可以直接解构接住。元组也能整体当参数传,元素静态类型为元组的列表,for-in 迭代变量位可以直接解构:

func main() -> int { val xs: list<(int, string)> = [(1, "甲"), (2, "乙")]; for (n, s) in xs { print(n, s); } return 0; }
1 甲 2 乙

list.Zip 与 map.Entries() 同样产出元组列表,解构、注解赋值与 .Item 成员都可用(见映射)。

判等:引用同一性

== / != 比实例身份,与 class、容器同律:各自构造的两个元组即使内容完全相同也不等,同一实例的别名才相等。要比内容,解构后逐分量比:

func main() -> int { val p = (1, "甲"); val q = (1, "甲"); val alias = p; print(p == q, p == alias); print(p.Item0 == q.Item0 && p.Item1 == q.Item1); return 0; }
False True True

可空元组照常参与:可空对可空、可空与非空混对都放行,解包后比身份,== null 判空照旧。

与容器的分工

定长且编译期已知结构的数据可以选元组,动态长度与同构元素选 List,异构集合退化为 list<any> 加运行期收窄,元组的优势是可以把结构提前到编译期。分量类型参与函数签名与泛型实参(list<(int, string)>),没有增删变异面。

注意

  • (1,) 与 () 都过不了解析:元组至少两个分量,两个以上分量的尾逗号 (1, 2,) 仍合法;空括号不是表达式。
  • 可空元组本身照常判空收窄:if (pay != null) 分支内可直接解构或 pay[0] 取分量,但对元组内的可空分量仍不收窄,需要先解构取出分量再判。
  • match 与 is 里的元组模式见模式,any 通道里的元组值可按类型形判形,if e is (int, string) p 命中时 p 绑定元组值,形状不符静默为 False。无类型的解构形 is (k, v) 不支持。
最后更新于 2026年10月9日