Skip to Content

泛型(Generics)

泛型把「类型的形状」与「具体类型」解耦:类型与函数都带类型参数,调用时才定下实例化。约束用 where 子句表达,约束面即能力面。

泛型类型

struct Box<T> { public var value: T; public func Get() -> T => value; public func Replaced(nv: T) -> Box<T> => new Box<T>() { value: nv }; } val bi = new Box<int>(); bi.value = 42; print(bi.Get(), bi.Replaced(7).Get()); val bs = new Box<string>(); bs.value = "字"; print(bs.Get());
42 7 字

Box<int> 与 Box<string> 是不同的实例化,各自有自己的成员面。嵌套实例化合法:Box<list<int>> 里装列表。

泛型函数

func First<T>(xs: list<T>) -> T? { if xs.Count == 0 { return null; } return xs[0]; } val empty = new list<string>(); print(First(empty) == null); val names = new list<string>(); names.Add("甲"); print(First(names));
True 甲

where 约束与运算符放行

约束写在返回类型之前(子句顺序 uses → fail → where → ->),约束声明「T 必须具备的能力」,泛型体内按约束放行运算:

import Math.*; func Sum2<T>(a: T, b: T) where T: Numeric -> T { return a + b; } print(Sum2(2, 3), Sum2(1.5, 2.5));
5 4

Numeric 是 std Math 的协议(四则 + 判等),内建标量隐式满足,a + b 按约束协议的运算符签名放行。约束可以写多条:where T: Ordered, Clone 单子句多约束,或多个 where 子句。

构造签名约束

约束协议声明 init() 时,泛型体内获得 new T() 的能力,实例化时按具体类型的构造器构造:

import Collections.*; protocol Makeable { init(); } struct Token { public var stamp: string = "生成"; } func Make<T>() where T: Makeable -> T { return new T(); } val t = Make<Token>(); print(t.stamp);
生成

没有 init 约束时 new T() 会直接编译期报错,因为无法确定对面的 T 是否允许被无参构造。

一元运算符约束

约束协议也能声明一元运算符。operator -(self) -> Self; 让泛型体里的 -x 放行:

protocol Neg { operator -(self) -> Self; } func Negate<T>(x: T) where T: Neg -> T { return -x; } print(Negate(5));
-5

实参侧按内建运算能力判定满足:uint / byte 没有一元负。

注意

  • 约束写在返回类型之前(uses → fail → where → ->),不能写到 -> 的右侧。
  • 约束可多约束并存:where T: Ordered, Clone 单子句多约束,或多个 where 子句各管一个类型参数。
  • 约束面没有的运算符用了报 MS3144,错误信息会指出该补充的协议。
  • list<T> / map<K, V> 都是泛型容器的现成范例,方法面见容器与文本。
最后更新于 2026年10月9日