Apple在这次WWDC20中有一章是Swift deep dive,对Swift的一些特性进行了深入探索和分析,看完觉得比较有意思,有必要单独拎出来写写,首先就来一起看看类型推断。
Swift使用类型推断来帮助开发者编写干净、简洁的代码,而不会损害类型安全性。我们将了解到Xcode是如何进行类型推断的,以及在无法进行有效推断时会发生什么,并了解Xcode如何跟踪错误,来帮助开发者快速理解和修复。
无处不在的类型推断
Swift广泛的使用类型推断,从而允许开发者可以忽略很多变量和表达式的类型或部分类型。
例如在变量声明中:
var x: Int = 0
完全可以忽略类型,从而简写成:
var x = 0
编译器会准确的推断出x的类型Int,而无需开发者显式声明。
为了方便后续分析编译器为此做了什么,我们先看看Session中给的例子,一款名为Fruta的订购冰沙应用(这个demo在很多Session中都有出现😂)。

为了实现某个功能,需要提供一个支持不同类型数据的接口,通过范型来实现:

由于编译器准确的类型推断,调用方并不需要关注类型信息,看起来非常简洁:

而如果没有类型推断,都需要开发者显式声明,那用起来无疑是一场灾难:

开发者显式声明所有类型是一项异常繁杂且无聊的工作,类型推断帮助开发者从中解放出来,更专注有意义的代码,提高效率。
接下来我们看看编译器是如何实现类型推断的。
编译器是如何实现的?
我们可以把类型推断看成智力拼图游戏,其原理是就是补充一块块拼图,根据某条线索填补一块拼图,又可以发现更多关于其它拼图的线索。(是不是有点意思😏)

接着以上面的接口为例,由于 smoothies 的类型是 [Smoothie],那么范型 Element 也就对应了 Smoothie 类型,因此我们完成了第一块拼图🧩:

既然知道了Element 也就对应了 Smoothie 类型,那么其他地方的 Element 自然也就可以填上了:

在此之前,我们无法知道 \Element.title 的类型,但经过上一步后,已经填补成了 \Smoothie.title,从而明确是 String 类型,因此范型 FilterKey 表示 String 类型,我们又找到了第二块拼图🧩:

现在只剩下了 RowContent,由于闭包只返回一个子视图 SmoothieRowView,那么显而易见,范型 RowContent 表示 SmoothieRowView 类型,至此我们找到了所有的拼图🧩。

其中灰色部分代码就是类型推断帮助我们做的事情,减少了相当一部分工作。
代码错误导致冲突
在上一节我们了解到了类型推断的过程,但是有时候不同的线索可能会相互冲突,这就意味着代码出现了错误。那么此时编译器如何判断错误?以及如何提供合适的辅助信息帮助开发者定位问题?
还是上面的例子,假如我们把 \Smoothie.title 替换为 \Smoothie.isPopular,其中 isPopular 一个 Bool 值。继续按照上面的方式填充拼图,此时范型 FilterKey 表示 Bool 类型:

那么在 isIncluded 闭包中,title 也对应 Bool 类型,但是 Bool 类型是没有 hasSubstring 方法的,拼图无法继续,编译器提示错误:

错误跟踪(Integrated error tracking)
Swift 通过将Integrated error tracking集成在类型推断算法中,在类型推断过程中,编译器会记录所有错误信息,同时用heuristics(启发法,例如试错法和排除法)修复错误,以便继续推断类型。
一旦类型推断完成,编译器将报告它收集到的所有错误,通常使用可操作的方法来自动修复源代码中的错误(下图中的Fix),或者编译器提示可能导致错误的具体类型的注释(下图左侧的提示)。Swift 5.2中很多错误使用到了Integrated error tracking,而Swift 5.3对所有错误消息都使用了这种新策略。

Integrated error tracking其实跟类型推断关系不大,只是顺着上一节的错误讲了下,视频里接下来还详细讲了例子,这里就不复述了,感兴趣的同学可以自己看~
相关Session
原创不易,文章有任何错误,欢迎批(feng)评(kuang)指(diao)教(wo),顺手点个赞👍,不甚感激!