Swift中风味各异的类型擦除实例详解.docx

Swift中风味各异的类型擦除实例详解.docx

  1. 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
  2. 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  3. 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多

Swift中风味各异的类型擦除实例详解

目录前言什么时候需要类型擦除通用包装器类型擦除闭包类型擦除结语

前言

Swift的总体目标是既强大到可以用于底层系统编程,又足够容易让初学者学习,这有时会导致相当有趣的情况当Swift的类型系统的力量要求我们部署相当高级的技术来解决乍一看可能更微不足道的问题。

大多数Swift开发人员会在某一时刻或另一时刻(通常是马上,而不是日后)会遇到这样一种情况,即需要某种形式的类型擦除才能引用通用协议。从本周开始,让我们看一下是什么使类型擦除在Swift中成为必不可少的技术,然后继续探索实现它的不同风味(Flavors),以及每种风味为何各有优缺点。

什么时候需要类型擦除

一开始,类型擦除一词似乎与Swift给我们的关注类型和编译时类型安全性的第一感觉相反,因此,最好将其描述为隐藏类型,而不是完全擦除它们。目的是使我们能够更轻松地与通用协议进行交互,因为这些通用协议对将要实现它们的各种类型具有特定的要求。

以标准库中的Equatable协议为例。由于所有目的都是为了根据相等性比较两个相同类型的值,因此Self元类型为其唯一要求的参数:

protocolEquatable{

staticfunc==(lhs:Self,rhs:Self)-Bool

}

上面的代码使任何类型都可以符合Equatable,同时仍然需要==运算符两侧的值都为同一类型,因为在实现上述方法时符合协议的每种类型都必须填写自己的类型:

extensionUser:Equatable{

staticfunc==(lhs:User,rhs:User)-Bool{

returnlhs.id==rhs.id

该方法的优点在于,它不可能意外地比较两个不相关的相等类型(例如User和String),但是,它也导致不可能将Equatable引用为独立协议(例如创建[Equatable]),因为编译器需要知道实际上确切符合协议的确切类型才能使用它。

当协议包含关联的类型时,也是如此。例如,在这里我们定义了一个Request协议,使我们可以在一个统一的实现中隐藏各种形式的数据请求(例如网络调用,数据库查询和缓存提取):

protocolRequest{

??associatedtypeResponse

??associatedtypeError:Swift.Error

??typealiasHandler=(ResultResponse,Error)-Void

??funcperform(thenhandler:@escapingHandler)

}

上面的方法为我们提供了与Equatable相同的权衡方法它非常强大,因为它使我们能够为任何类型的请求创建通用抽象,但也使得无法直接引用Request协议本身,例如这:

classRequestQueue{

//报错:protocolRequestcanonlybeusedasageneric

//constraintbecauseithasSelforassociatedtyperequirements

funcadd(_request:Request,

handler:@escapingRequest.Handler){

解决上述问题的一种方法是完全按照报错消息的内容进行操作,即不直接引用Request,而是将其用作一般约束:

classRequestQueue{

funcaddR:Request(_request:R,

handler:@escapingR.Handler){

上面的方法起作用了,因为现在编译器能够保证所传递的处理程序确实与作为请求传递的Request实现兼容因为它们都基于泛型R,而后者又被限制为符合Request协议。

但是,尽管我们解决了方法的签名问题,但仍然无法对传递的请求进行实际的处理,因为我们无法将其存储为Request属性或[Request]数组,这将使继续构建我们的RequestQueue变得困难。也就是说,除非我们开始进行类型擦除。

通用包装器类型擦除

我们将探讨的第一种类型擦除实际上并没有涉及擦除任何类型,而是将它们包装在一个我们可以更容易引用的通用类型中。继续从之前的RequestQueue示例开始,我们首先创建该包装器类型该包装器类型将捕获每个请求的perform方法作为闭包,

文档评论(0)

152****2426 + 关注
实名认证
内容提供者

该用户很懒,什么也没介绍

1亿VIP精品文档

相关文档