Swift 类型推断

2,897 阅读4分钟

「这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战

Swift 是一种静态类型语言,这意味着我们声明的每个属性、常量和变量的类型都需要在编译时指定。 但是,这通常不需要手动完成,而是编译器能够自行计算出范围广泛的类型信息——这要归功于 Swift 支持类型推断这一事实。

例如,这里我们声明了一些常量——完全没有指定任何类型,因为编译器能够根据分配的值推断出这些信息:

image.png

作为比较,如果我们改为手动指定每个常量的类型,则上面的赋值如下所示:

image.png

因此,类型推断在使 Swift 的语法尽可能轻量方面发挥了重要作用,不仅在变量声明和其他类型的赋值方面,而且在许多其他类型的情况下也是如此。

例如,这里我们定义了一个描述各种联系人的枚举,以及一个让我们加载属于某种类型的联系人值数组的函数:

image.png

虽然我们通常会通过指定类型和案例来引用上述枚举的成员(例如 ContactKind.friend),但由于类型推断,我们可以在上下文中引用案例时完全省略类型的名称 其中类型是已知的——比如调用我们上面的函数时:

image.png

真正酷的是,上面的“点语法”不仅适用于枚举情况,它也适用于引用任何静态属性或方法。 例如,这里我们使用静态属性扩展了 Foundation 的 URL 类型,该属性创建了一个指向该网站的 URL:

image.png

现在,当调用任何接受 URL 参数的方法(例如新的基于组合的 URLSession API)时,我们可以像这样简单地引用上述属性:

image.png

真的很整齐! 然而,虽然类型推断是一个非常有用的特性,但在某些情况下,我们可能需要指定一些额外的类型信息才能达到我们想要的结果。

这种情况的一个非常常见的例子是在处理数字类型时。 当一个数字字面量分配给一个变量或常量时,默认情况下它会被推断为 Int 类型——这是一个完全合理的默认值——但如果我们希望使用其他数字类型,例如 Double 或 Float,我们' 将需要手动指定这些类型。 这里有几种方法可以做到这一点:

image.png

另一种我们可能需要为编译器提供额外类型信息的情况是调用具有通用返回类型的函数时。

例如,在这里我们使用通用方法扩展了内置的 Bundle 类型,该方法让我们可以轻松加载和解码我们在应用程序中捆绑的任何 JSON 文件:

image.png

现在假设在我们的应用程序开发过程中,直到我们的真实服务器和网络代码启动并运行,我们希望从捆绑的 JSON 文件中解码以下用户类型的实例:

image.png

但是,如果我们像这样调用 decodeJSONFile 方法,最终会出现编译器错误:

image.png

那是因为我们将任何给定 JSON 文件解码成的确切类型取决于泛型类型 T 在每个调用站点实际引用的内容——并且由于我们没有向编译器提供上述任何此类信息,我们最终会 有错误。 在这种情况下,编译器根本无法知道我们希望解码 User 实例。

为了解决这个问题,我们可以使用与上面相同的技术来指定不同类型的数值,或者给我们的用户常量一个明确的类型,或者使用 as 关键字——像这样:

image.png

但是,如果我们要在已知所需返回类型的上下文中调用 decodeJSONFile 方法,那么我们可以再次让 Swift 的类型推断机制为我们找出这些信息——就像在这种情况下,我们已经定义了 一个名为 MockData 的包装器结构,它具有一个用户类型的属性,我们将结果分配给:

image.png

以上就是对 Swift 类型推断能力的快速介绍。 同样重要的是要指出,类型推断确实有与之相关的计算成本,幸运的是,这完全发生在编译时(因此它不会影响我们应用程序的运行时性能),但它仍然可以是好的 在处理更复杂的表达式时要记住。 但是,如果我们确实遇到了一个需要编译器很长时间才能弄清楚的表达式,那么我们总是可以使用上述技术之一来手动指定这些类型。