在 Swift 的世界中,如果我们将协议称之为国王,那么泛型则可以视作皇后,所谓一山不容二虎,当我们把这两者结合起来使用的时候,似乎会遇到极大的困难。那么是否有一种方法,能够将这两个概念结合在一起,以便让它们成为我们前进道路上的垫脚石,而不是碍手碍脚的呢?答案是有的,这里我们将会使用到类型擦除 (Type Erasure) 这个强大的特性。
在本次 AltConf 的讲演中,Hector Matos 讲解了在 Swift 中将泛型和协议结合起来使用时的一些缺陷,然后具体介绍了类型擦除的含义。更为重要的是,他通过一个真实的 App Store 上架应用,解释了为什么在同时使用协议和泛型时需要类型擦除的帮助。到目前为止,最常见的一个问题就是为什么我们会需要在 Swift 当中使用类型擦除呢?
在本次讲演的最后,您会对如何在应用中更好地将协议和泛型结合起来有着更好的思路和想法,您会发现类型擦除非常简单,而且十分有用。
今天我要给大家分享的主题是:神奇的类型擦除 ( 通过这个「魔法」,我觉得我将成为一名神奇的「魔法师」 ),我将会用现场编程的方式来给大家分享,这对我来说是一个不小的挑战。关于类型擦除,网上有不少优秀的演讲 (例如 Gwen 的 什么是类型擦除 ),此外也有不少的优秀文章(例如 Russ Bishop、Rob Napier 的,文章的链接参见文末)。
当您开始学习一门编程语言的时候,您很有可能是从 string
、 int
或者 float
开始学习的:这些都是所谓的「 具体类型 (concrete type) 」,也就是编译器能够在编译时确定此类型所占的空间大小——这使得编译器对具体类型的处理非常友好。如果某个类型可以被初始化——也就是说您可以调用它的初始化方法——那么就说明它是一个具体类型。
另外一种类型就是「 抽象类型 (abstract type) 」( 也被称为存在类型 (existential) )。对于抽象类型来说,编译器无法知道这个类型的确切功能。当编译器处理抽象类型的时候,它无法知晓其所占的空间大小;甚至可能会认为这个类型是不存在的。事实上,您很可能见到过这样的错误描述「我无法为您找寻到此类型」。
在 Swift 当中,抽象类型的普遍表述方式使用 associatedType
来描述的,之前我们是使用 typealias
来定义的,此外泛型 <T>
同样也是一个抽象类型。如果编译器无法在编译时知晓类型的所占空间大小,或者您无法将其初始化,也就是说您没办法调用它的 init
的方法:那么就说明这个类型很可能是抽象类型。
什么是 Swift 中的类型擦除?
有很多地方会用到 类型擦除 ,并且它们的作用的各不相同。在 Java 当中,它用来让编译器知晓其相关内容,它会抹除 <T>
的存在,然后用一个具体类型将其替代。在 Swift 当中,我们不必处理这些琐事,我们可以自行实现——有很多您可以选择的实现方式。对于类型擦除来说,绝大多数语言当中的基本概念是相同的,但是在 Swift 当中,它解决了这个问题。
Get more development news like this
让我们来看一下这个协议, SpellDelegate
当中有一个名为 SpellType
的 associatedtype
。假设我们需要执行一个委托操作,从而允许您使用符咒来攻击某个巫师。因此您就试图去使用这个委托方法,然后将其声明为了一个属性,这个时候您就会得到一个错误:「协议 SpellType
只能够作为泛型约束 (Generic Constraint) 来使用,因为它内含了必需的 Self
或者 associatedtype
。」
类型擦除就是在代码中 让抽象类型具体化 的一个过程。很多人往往会选择开始讲解分类原理、讲解类型原理,甚至讲解编译器内部的一些规则。但是我现在不想讲述这些内容,我想要尽可能让这个概念变得更简单一些。
https://www.codercto.com/a/4731.html