Skip to Content

扩展(Extension)

extension 给既有类型注入新方法:类型的源码不用动,方法面的补全与调用都像原生成员。标量、用户类型都能扩展。

标量接收者

extension string { public func Shout() -> string => self.ToUpper() + "!"; } extension int { public func Squared() -> int => self * self; } print("哼".Shout()); val n = 5; print(n.Squared());
哼! 25

self 指接收者本身。字面量上直接调(7.Squared())、变量上调用,都成立。

用户类型扩展

struct Point { public var x: int = 0; public var y: int = 0; } extension Point { public func Manhattan() -> int { return (x < 0 ? -x : x) + (y < 0 ? -y : y); } public func Show() -> string => $"({x}, {y})"; } val p = new Point() { x: 3, y: -4 }; print(p.Manhattan(), p.Show());
7 (3, -4)

扩展体里直接访问目标类型的字段(含 private 的同模块字段面)。Point 自己不用改一行。

扩展体能声明什么

扩展体里能声明的是「注入面」:func、operator 重载、属性、static func 与 static event、event 与 event prop(含 before / after / finally 管线段,随注入接线发射)、外加 impl 子句。运算符与属性经扩展注入后就是目标类型的一员:

struct Pt { public var x: int = 0; public var y: int = 0; } extension Pt { public operator +(self, o: Pt) -> Pt => new Pt() { x: x + o.x, y: y + o.y }; public prop Norm: int => x * x + y * y; } val a = new Pt() { x: 1, y: 2 }; val b = new Pt() { x: 10, y: 20 }; val s = a + b; print(s.x, s.y, a.Norm);
11 22 5

a + b 走扩展提供的 operator +,a.Norm 走扩展属性,调用位与原生成员无异。反向边界同样清楚:

  • init 与 deinit 解析拒:构造是类型本体的事。
  • static / const 的存储形成员(static val / var / prop、const)定向拒(静态存储挂不到被扩展类型上),静态面只放 static func 与 static event。
  • event 与 event prop 经扩展注入全链路可用:声明、emit、~> 订阅、写位广播、管线段发射照常。
  • bind 不在扩展体收,绑定声明留在类型体。

激活规则

扩展成员经 import 所在模块自动激活:定义在哪个模块,import 那个模块就可用。

泛型目标

extension Crate<T> // 注入泛型声明本体 extension Crate<int> // 具体化:只注入 Crate<int> 实例化

裸标识符永远是类型参数,想具体化到某个实例化就写全 Crate<int>。

具体化版与泛型版同签名共存时具体化版胜出。想具体化到用户命名类型必须点分前缀(Crate<Mod.Foo>)。目标类型实参要么全为类型参数、要么全为具体类型。

遮蔽与重载共存

类型自有方法遮蔽扩展的同名同签名方法,签名不同则正常重载共存:

class Slot<T> { public var item: T; public func Describe() -> string => $"自有 {item}"; } extension Slot { public func Describe() -> string => $"扩展 {item}"; public func DescribeLoud() -> string => $"扩展 {item}!"; } val s = new Slot<int>(); s.item = 3; print(s.Describe()); print(s.DescribeLoud());
自有 3 扩展 3!

Describe 调到自有版本,扩展版被遮蔽。DescribeLoud 只有扩展提供,直接可用。

扩展与协议

extension T impl P 把协议满足性直接传播给目标类型:扩展体提供 P 要求的成员,T 在协议位与泛型约束位都按满足判定,T 自己不用写 impl:

protocol Pinger { func Ping(self) -> string; } extension Holder impl Pinger { public func Ping(self) -> string => "ext"; } class Holder { } val p: Pinger = new Holder(); print(p.Ping());
ext

扩展注入的成员同样可以满足类型自己声明的 impl P 要求。反过来,挂到协议身上的扩展成员不会变成协议的新要求,协议的要求集只看协议声明链。协议的 static 成员也惯用扩展实现,见协议的 Lerpable 例。

标量目标有一条硬边界:extension int impl P 的成员直调可用,但标量进不了协议位(val p: P = 5; 报 MS3101)。

注意

  • 本类型自有方法遮蔽扩展的同名同签名方法,同名不同签名是正常重载。
  • 内建容器(list / set / map / array)方法面封闭,不可作扩展目标(MS4008)。
  • 扩展不能加字段、不能改类型的存储布局。
最后更新于 2026年10月9日