活用 Swift 类型推断
Posted 老司机技术周报
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了活用 Swift 类型推断相关的知识,希望对你有一定的参考价值。
关注有礼,文章末尾有粉丝抽奖福利。❤️
Session: https://developer.apple.com/videos/play/wwdc2020/10165/
概述
Swift 广泛使用类型推断为开发者提供简洁的语法,同时保证代码的安全性。在本主题中,我们将讨论类型推断的实现原理,了解如何使用 Xcode 提供的辅助信息,快速修正代码错误。
本文基于WWDC20 - Embrace Swift type inference 梳理
SwiftUI 中的类型推断
我们团队在做一款名为『Fruta』的订购冰沙应用。在右侧的预览中,你可以看到当前的冰沙列表。我想增加一个功能:用户可以输入关键字,列表页内容根据输入内容产生变化。
先来通过代码看看当前显示全部冰沙列表是如何实现的:在 SmoothieList 中,通过 smoothies 数组映射生成 SmoothieRowView 列表。
为了增加搜索功能,SmoothieList 需要新增 @State 属性 searchPhrase 来存储用户输入的字符串。
List 需要调整为 FilteredList,FilteredList的构造器有三个参数:smoothies 数组,filterBy KeyPath 过滤特定属性,isIncluded 闭包返回对应属性的包含关系。调整后的代码如下:
从调用者来看一切非常自然,然而 FilteredList 的初始化过程很大程度上依赖类型推断。让我们来看看是什么原因导致这段调用依赖类型推断,以及调用上下文如何利用类型推断提供简洁易用的的接口。
为了理解调用过程省略的细节,我们先看看 FilteredList 的声明。FilteredList 是一个通用的视图类型,它需要支持组合不同类型的数据、过滤属性以及视图,这些都是通过范型来提供的。
FilteredList 引入 Element、FilterKey、RowContent 三个范型参数,他们起到占位符的作用,在调用时被具体类型所替代。这些占位符所对应的具体类型,要么由调用者显式指定,要么通过类型推断来生成。
在本例中,Element 是数组元素数据类型的占位符,FilterKey 是元素特定属性类型的占位符,RowContent 是列表每行显示视图类型的占位符。
FilteredList 构造器的每一个参数的类型信息以及调用时的上下文,都会作为类型推断的线索之一。我们稍后会看到这一点是如何工作的,先来看看 FilteredList 构造器每个参数的类型细节:
-
data: [Element]
:data 是一个 Element 类型的数组,提供视图将要映射的数据 -
key: KeyPath<Element, FilterKey>
:要过滤的特定属性类型,基本类型为 Element,值类型为 FilterKey -
isIncluded: @escaping (FilterKey) -> Bool
:一个函数闭包,FilterKey 类型数据作为输入,返回 Bool 判断是否需要过滤。这个闭包需要持有,所以声明 @escaping。 -
@ViewBuilder rowContent: @escaping (Element) -> RowContent
:另一个函数闭包,输入是一个元素数据 Element,返回 RowContent 视图。同样因为需要持有,声明 @escaping。@ViewBuilder 是 SwiftUI DSL 语法,可以把闭包中多个子视图自动组合为元组供父视图使用。
这就是 FilteredList 构造器完整类型信息,下面我们看看调用过程如何来进行完整的类型推断。
把构造器声明和调用过程放在一起,你可以看到调用过程非常简洁,同时它仍然为编译器提供了完整的类型信息。
如果我们在代码中显式声明所有参数类型,调用会是什么样子?我们先通过 FilteredList 构造器补充参数类型,范型对应的类型先用占位符表示。
相比之前的调用,已经啰嗦很多,这还不够,类型推断还需要补充对应占位符的类型信息,完善调用阶段全部的类型细节。
手动填入所有类型信息是一项繁杂且无聊的工作,类型推断让调用者从类型信息中解放出来,更快的编写代码。
让我们来谈谈编译器是如何把占位符转换成具体类型的。
类型推断过程
以上是关于活用 Swift 类型推断的主要内容,如果未能解决你的问题,请参考以下文章 变量“offerCardsShuffled”推断为“()”类型,这可能是意外的