介绍
SE-0358, Swift5.7 已实现。
SE-0346 已经引入了主要关联类型特性。本篇提议目的是为了在 Swift 标准库中使用此特性,为现有协议支持主要关联类型。此外,这篇提议还提供了一些通用的API设计建议,会对协议作者在添加对该特性的支持时提供便利。
API 设计指南
主要关联类型为协议设计增加了一个新的方向。对每个具有多个关联类型要求的协议,我们要谨慎的确认哪个类型为主要关联类型。一方面希望开发者尽可能使用速记语法快速记住,另一方面我们只有一次机会来决定选用哪个主要关联类型,一旦协议确立主要关联类型,后续关于协议的更改都会受到影响。
下面列举的这些指南帮助我们在标准库采用主要关联类型。由于这个新特性的使用,目前没有大量实际经验来沉淀一套通用的准则,所以这套指南后续会逐渐完善。指南包括四个方面:
1. 让用法为设计提供信息
如果你正在为现有的协议添加一个主要关联类型,先看看该协议关联的类型中哪些是受限制的。是否有一个类型比其他类型使用的多?如果是,那么该类型就是主要关联类型的不错选择。
举例说明。拿Sequence
来说,使用场景中更多是限制Element
, 而不是Iterator
. 后者几乎在where
语句没有被提及。很明显,Element
是主要关联类型。
在设计新协议时,需要考虑哪个类型最常用,也就是最常约束类型。有时候最常用的类型,甚至都不是你计划作为关联类型的其中之一。
看个例子。Swift5.7中的新协议Clock
只有Instant
一个关联类型。在实际使用中,开发者更多使用的类型是Instant.Duration
而不是Instant
类型本身。时钟往往与一瞬间紧密相连,无法成为有用的约束目标,在实际场景中使用瞬间这种场景较少。some Clock<ContinuousClock.Instant>
实际上只是ContinuousClock
的拼写方式。另一方面,some Clock<Swift.Duration>
捕获以物理秒为单位测量流逝时间的所有 clock, 这个信息更为实用,因此,最后决定使用Clock.Duration
作为主要关联类型。
2. 使用场景考虑清晰度
为了防止使用混淆或者不清晰,熟悉协议的人应该能够正确理解同类型约束的含义,例如some Sequence<Int>
。轻量级约束规范与泛型参数具有相同的括号语法,包括相同的限制。特别是不支持此类列表中的参数标签,这就无法清楚表明所提供的类型名称的作用。例如,Foo<Int, String>
中没有提供通用参数Int
和String
的明确作用提示。
主要关联类型的最佳候选者往往是那些与协议本身有简单、明显关系的类型。有个好的小窍门就是,如果关系可以用一个简单的介词来描述,那么相关类型可能会成为一个可行的主要关联类型:
Collection
ofInt
Identifiable
ofString
SIMD
ofFloat
RawRepresentable
byInt32
3. 不是所有的协议都需要主要关联类型
不能把添加主要关联类型当成实现协议的义务去做。如果在实际使用不希望限制某个类型,或者说有多个关联类型都是平等使用,那么此时不要去设置主要关联类型。例如,在泛型函数声明预计不会提及ExpressibleByIntegerLiteral
,所以没有必要把该协议的关联类型IntegerLiteral
设置为主要关联类型。
4. 把主要关联类型的数量限制为1
在大多数情况下,最好不要在任何协议上声明多个主要关联类型。保持一个最好。
提议方案
下面表格列举了标准库中带关联类型的所有公共协议,以及它们提议的关联类型。
Protocol | Primary | Others |
---|---|---|
|
|
|
|
| -- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| -- |
|
| -- |
|
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
|
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
|
|
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
|
|
|
|
| -- |
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
| -- |
|
在 Swift5.6 中,下面这些协议没有关联类型:
代码语言:Swift复制Equatable, Hashable, Comparable, Error, AdditiveArithmetic,
DurationProtocol, Encodable, Decodable, Encoder, Decoder,
UnkeyedEncodingContainer, UnkeyedDecodingContainer,
SingleValueEncodingContainer, SingleValueDecodingContainer,
ExpressibleByNilLiteral, CodingKeyRepresentable,
CustomStringConvertible, LosslessStringConvertible, TextOutputStream,
TextOutputStreamable, CustomPlaygroundDisplayConvertible,
CustomReflectable, CustomLeafReflectable, MirrorPath,
RandomNumberGenerator, CVarArg, Sendable, UnsafeSendable, Actor,
AnyActor, Executor, SerialExecutor, DistributedActorSystemError
详细设计
代码语言:Swift复制public protocol Sequence<Element>
public protocol IteratorProtocol<Element>
public protocol Collection<Element>: Sequence
public protocol MutableCollection<Element>: Collection
public protocol BidirectionalCollection<Element>: Collection
public protocol RandomAccessCollection<Element>: BidirectionalCollection
public protocol RangeReplaceableCollection<Element>: Collection
public protocol Identifiable<ID>
public protocol RawRepresentable<RawValue>
public protocol RangeExpression<Bound>
public protocol Strideable<Stride>: Comparable
public prococol SetAlgebra<Element>: Equatable, ExpressibleByArrayLiteral
public protocol SIMD<Scalar>: ...
public protocol Clock<Duration>: Sendable
public protocol InstantProtocol<Duration>: Comparable, Hashable, Sendable