每天了解一点不一样的 Swift 小知识

代码截图

image.png

小笔记

typealias 是什么

与 typealias 关联的概念叫做类型别名,它就是给现有类型定义另一个名字。

你可以使用 typealias 关键字来定义类型别名,更多详情可以参考 基础部分 的章节

这与 Objective-C 里面的 typedefdefine 的作用上有一些相似之处。

typealias 的使用场景

使用场景主要有 2 个:

一个就是今天图例里提到的,减少代码长度。

另一个就是合理的使用 typealias ,会让特定上下文的程序可读性会更强。试想我们用 Swift 做一些数学计算,我们定义了这样一段代码

let distance: Double = distanceBetweenPoint(origin, toLocation: point)

虽然看起来似乎没什么大的毛病,但我们总是要记住 distance 是一个 double 类型,在这段代码里面表示两个点的距离,这让代码的数学味道淡了一些

但如果我们提前用 typealias 定义的话,代码将变为下面的样子,代码理解起来更容易,阅读体验也更流畅。

typealias Distance = Double
let distance: Distance = distanceBetweenPoint(origin, toLocation: point)

需要注意的地方

typealias 还会经常用在泛型的场景下,但是这地方有一些需要注意的地方

typealias 是单一的,也就是说你必须指定将某个特定的类型通过 typealias 赋值为新名字,而不能将整个泛型类型进行重命名。

例如下面的代码就会报错

class Person<T> {}
typealias Coder = Person
typealias Coder = Person<T>
typealias Coder<T> = Person<T>

要想使用 typealias 就需要这么写,即明确泛型中的不确定因素,使其成为特定的类型

class Person<T> {}
typealias Name = String
typealias Coder = Person<Name>

还有一个有意思的地方是,Swift 中是没有泛型接口的,但是使用 typealias,我们可以在接口里定义一个必须实现的别名,例如 Swift Standard Library 里的 Sequence 就用到了这个套路,下面是其中的一段代码

extension DropFirstSequence : Sequence {
/// A type representing the sequence's elements.
public typealias Element = Base.Element
/// A type that provides the sequence's iteration interface and
/// encapsulates its iteration state.
public typealias Iterator = Base.Iterator
public typealias SubSequence = AnySequence<DropFirstSequence<Base>.Element>
/// Returns an iterator over the elements of this sequence.
@inlinable public __consuming func makeIterator() -> DropFirstSequence<Base>.Iterator
@inlinable public __consuming func dropFirst(_ k: Int) -> DropFirstSequence<Base>
}

在实现这些接口时,我们不仅需要实现指定的方法,还要实现对应的 typealias,这其实是一种对于接口适用范围的抽象和约束。