Skip to Content

订阅句柄与事件值(Subscription)

每次订阅产出一个 subscription 句柄,事件名在值位产出一个事件值。句柄管退订与统计,事件值管把频道当数据传递。

event Ticked(n: int); event MovedX(dx: int); var total = 0; func Add(n: int) { print($"加 {n}"); } func Track(n: int) { total += n; }

订阅句柄的三个成员

~> / <~ / once ~> 表达式的值都是 subscription:Cancel() 退订,IsCancelled 查状态,TriggerCount 数触发次数:

val h: subscription = Ticked ~> Add; emit Ticked(1); print("已触发", h.TriggerCount, "取消?", h.IsCancelled); h.Cancel(); emit Ticked(2); print("取消?", h.IsCancelled); h.Cancel();
加 1 已触发 1 取消? False 取消? True

取消后再 emit 不再送达,重复 Cancel() 是无害的。

once:触发一次自动退

once ~> 订阅在首次触发后自动转已取消:

val single = Ticked once ~> Add; emit Ticked(10); emit Ticked(20); print("once 取消?", single.IsCancelled, "次数", single.TriggerCount);
加 10 once 取消? True 次数 1

匿名 lambda 的退订

匿名 lambda 订阅同样拿到句柄,保存句柄即可退订:

val lh = Ticked ~> (n: int) => { total += n; }; emit Ticked(100); lh.Cancel(); emit Ticked(1000); print("total =", total);
total = 100

事件一等值

事件名出现在值位就是事件值,类型是形状类型 event<P...>。相等按声明身份判定(同声明才相等),emit 经值发射照跑声明管线:

val v: event<int> = MovedX; print(v == MovedX); emit v(7);
True

「一组频道」可以用事件值列表表达,循环订阅、循环退订:

val watch: list<event<int>> = [MovedX, Ticked]; for e in watch { e ~> Track; } emit MovedX(3); emit Ticked(4); print("total =", total);
total = 107

注意

  • 事件值的载荷形状必须相同:多、少、位型不符都不能互赋。
  • eventof(obj.Prop) 把 event prop 频道取成 event<T, T> 值(载荷旧值、新值),之后与普通事件值同用。
  • 泛型事件的类型实参从 handler 形参或 emit 实参推断。
最后更新于 2026年10月10日