标准库中的主要关联类型

2022-11-29 17:54:03 浏览数 (2)

介绍

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>中没有提供通用参数IntString的明确作用提示。

主要关联类型的最佳候选者往往是那些与协议本身有简单、明显关系的类型。有个好的小窍门就是,如果关系可以用一个简单的介词来描述,那么相关类型可能会成为一个可行的主要关联类型:

  • Collection of Int
  • Identifiable of String
  • SIMD of Float
  • RawRepresentable by Int32

3. 不是所有的协议都需要主要关联类型

不能把添加主要关联类型当成实现协议的义务去做。如果在实际使用不希望限制某个类型,或者说有多个关联类型都是平等使用,那么此时不要去设置主要关联类型。例如,在泛型函数声明预计不会提及ExpressibleByIntegerLiteral,所以没有必要把该协议的关联类型IntegerLiteral设置为主要关联类型。

4. 把主要关联类型的数量限制为1

在大多数情况下,最好不要在任何协议上声明多个主要关联类型。保持一个最好。

提议方案

下面表格列举了标准库中带关联类型的所有公共协议,以及它们提议的关联类型。

Protocol

Primary

Others

Sequence

Element

Iterator

IteratorProtocol

Element

--

Collection

Element

Index, Iterator, SubSequence, Indices

MutableCollection

Element

Index, Iterator, SubSequence, Indices

BidirectionalCollection

Element

Index, Iterator, SubSequence, Indices

RandomAccessCollection

Element

Index, Iterator, SubSequence, Indices

RangeReplaceableCollection

Element

Index, Iterator, SubSequence, Indices

LazySequenceProtocol

--

Element, Iterator, Elements

LazyCollectionProtocol

--

Element, Index, Iterator, SubSequence, Indices, Elements

Identifiable

ID

--

RawRepresentable

RawValue

--

RangeExpression

Bound

--

Strideable

Stride

--

SetAlgebra

Element

ArrayLiteralElement

OptionSet

--

Element, ArrayLiteralElement, RawValue

Numeric

--

IntegerLiteralType, Magnitude

SignedNumeric

--

IntegerLiteralType, Magnitude

BinaryInteger

--

IntegerLiteralType, Magnitude, Stride, Words

UnsignedInteger

--

IntegerLiteralType, Magnitude, Stride, Words

SignedInteger

--

IntegerLiteralType, Magnitude, Stride, Words

FixedWidthInteger

--

IntegerLiteralType, Magnitude, Stride, Words

FloatingPoint

--

IntegerLiteralType, Magnitude, Stride, Exponent

BinaryFloatingPoint

--

IntegerLiteralType, FloatLiteralType, Magnitude, Stride, Exponent, RawSignificand, RawExponent

SIMD

Scalar

ArrayLiteralElement, MaskStorage

SIMDStorage

--

Scalar

SIMDScalar

--

SIMDMaskScalar, SIMD2Storage, SIMD4Storage, ..., SIMD64Storage

KeyedEncodingContainerProtocol

--

Key

KeyedDecodingContainerProtocol

--

Key

ExpressibleByIntegerLiteral

--

IntegerLiteralType

ExpressibleByFloatLiteral

--

FloatLiteralType

ExpressibleByBooleanLiteral

--

BooleanLiteralType

ExpressibleByUnicodeScalarLiteral

--

UnicodeScalarLiteralType

ExpressibleByExtended- GraphemeClusterLiteral

--

UnicodeScalarLiteralType, ExtendedGraphemeClusterLiteralType

ExpressibleByStringLiteral

--

UnicodeScalarLiteralType, ExtendedGraphemeClusterLiteralType, StringLiteralType

ExpressibleByStringInterpolation

--

UnicodeScalarLiteralType, ExtendedGraphemeClusterLiteralType, StringLiteralType, StringInterPolation

ExpressibleByArrayLiteral

--

ArrayLiteralElement

ExpressibleByDictionaryLiteral

--

Key, Value

StringInterpolationProtocol

--

StringLiteralType

Unicode.Encoding

--

CodeUnit, EncodedScalar, ForwardParser, ReverseParser

UnicodeCodec

--

CodeUnit, EncodedScalar, ForwardParser, ReverseParser

Unicode.Parser

--

Encoding

StringProtocol

--

Element, Index, Iterator, SubSequence, Indices, UnicodeScalarLiteralType, ExtendedGraphemeClusterLiteralType, StringLiteralType, StringInterPolation, UTF8View, UTF16View, UnicodeScalarView

CaseIterable

--

AllCases

Clock

Duration

Instant

InstantProtocol

Duration

--

AsyncIteratorProtocol

--

Element

AsyncSequence

--

AsyncIterator, Element

GlobalActor

--

ActorType

DistributedActor

--

ID, ActorSystem, SerializationRequirement

DistributedActorSystem

--

ActorID, SerializationRequirement, InvocationEncoder, InvocationDecoder, ResultHandler

DistributedTargetInvocationEncoder

--

SerializationRequirement

DistributedTargetInvocationDecoder

--

SerializationRequirement

DistributedTargetInvocationResultHandler

--

SerializationRequirement

在 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

0 人点赞