首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Swift高级分享-Swift中下标的强大功能

使用下标访问各种集合中的元素,如数组和字典,不仅在Swift中很常见,而且在几乎所有相对现代的编程语言中都是如此。但是,下标方式实际上是在Swift中实现的,它既非常独特,又非常强大 - 因为它允许我们将自己的类型的下标API添加到标准库中。

本周,我们来看看下载是如何在Swift中运行的,以及一些将它融入我们设计API的方式 - 包括一些在Swift 5.1中添加的全新功能。

下标与方法

可以说,下标的最大好处是它在呼叫站点提供的令人难以置信的轻量级语法。而不是必须使用我们需要记住或查找的名称来调用特定方法,而下标允许我们仅使用其索引或键来检索值:

只需将上面两个API与它们的方法等价物进行比较:

但是,虽然下标对于一组有点狭窄的用例非常方便,但如果在动态获取和设置值之外使用,也可能导致相当混乱的代码。例如,这行代码导致发送通知并不十分清楚:

由于上面的API用于执行操作,而不是分配值,因此可以说一个好的老式方法更合适:

所以下标绝对不是方法的替代品,而是一种更容易提供对一组基础值的访问的方法 - 无论是集合,数据库还是使用密钥路径访问的模型。

自定义下标

假设我们正在构建一个项目管理应用程序,让我们的用户通过将他们放在二维网格上来组织他们的任务。为了简单起见,我们将网格建模为行的有序值数组,给定的水平宽度:

虽然可以通过直接下标数组(例如第三个任务)来访问第一行中的任何任务,但是一旦我们开始垂直遍历网格,我们必须做一些基本的数学计算,以便计算对应于a的索引。给定的X和Y坐标集。为了避免代码重复和潜在错误,我们将这些计算封装在一个方法中 - 如下所示:

请注意,我们可以使用我们的坐标,而不是签名整数,这将节省我们的检查。但是,这会将验证负担推向我们的API用户,因为在调用我们的API之前首先必须将所有值转换为- 这将使得使用起来更加麻烦。

就像我们之前看过的假设和API一样,上面的方法有效,但有点不必要的冗长。实际上,因为我们只是从集合中访问元素 - 所以我们也提供上述API的下标,如下所示:

只读下标与Swift中的方法非常相似,只是它们使用关键字,而不是后跟名称。

有了上述内容,我们现在可以非常轻松地访问网格中的任何任务,只需使用我们感兴趣的坐标下标即可:

下标的原因之所以如此,是因为访问网格中的图块的概念与从数组或字典中检索值非常相似 - 而且因为它很容易理解并引用坐标,而不需要任何额外的措辞。

超载

就像方法和自由函数一样,可以重载Swift下标,为不同的输入集提供不同的功能。例如,假设我们想要提供一个额外的下标API来访问我们网格中的整行任务,可以这样做:

上面我们返回一个,而不是一个正确的,以避免每次访问我们的下标时复制我们返回的任务范围。这与上周为计算属性提供恒定时间复杂度的方法非常相似。

虽然我们的新下标在上面看起来很棒,但是一旦我们开始使用它,我们会发现它在调用网站上看起来很模糊 - 因为默认情况下下标没有得到外部参数标签,使它看起来像我们只是访问它单个任务,而不是整行:

歧义是部署下标时最突出的风险之一,因为我们需要确保基于下标的API的所有用法都能让任何人阅读我们的代码足够的上下文来理解正在发生的事情 - 这绝对不是上面的情况。

值得庆幸的是,上述问题可以很容易修复,因为我们实际上可以将外部参数标签添加到下标中 - 如果我们想要 - 通过在函数参数之前添加自定义外部标签的完全相同的方式 - 通过在名称之前添加标签一个参数:

通过上面的调整,我们的调用站点现在看起来更加清晰 - 正如我们在使用新的下标时明确指出的那样:

在我们设计任何类型的API时,在减少详细程度和仍然在呼叫站点提供足够清晰度之间达成这种平衡是一个常见的挑战,但在使用下标时尤为重要 - 因为它们默认不包括任何类型的措辞所有。

吸气剂,制定者和仿制药

下标和函数的另一个共同点是它们可以是通用的,这使我们能够在不会给我们带来无类型(或)值的情况下保留类型安全性。

作为示例,让我们看一下如何使用该功能来提高常用系统API 的类型安全性。

我们将从泛型类型开始,它带有我们正在寻找的类型(几乎像幻像类型)。我们还将添加一个读写下标,它允许我们以类型安全的方式检索和存储值:

我们块中出现的上述变量由编译器自动生成,并表示使用我们的下标分配的新值 - 与使用属性观察器时完全相同。

有了上述内容,我们现在可以使用计算的类似工厂的属性来扩展以创建我们的密钥 - 每个密钥与其相应值的确切类型相关联,从而为我们提供完整的类型安全性:

由于静态属性可以与点语法一起使用,因此我们现在可以轻松使用这样的值:

太酷了!但也许更酷的是,尝试存储不正确类型的值现在会给我们一个编译器错误:

我们还可以通过添加接受默认值的第二个重载来为我们的新类型安全的下标API提供额外的功能 - 就像工作方式一样:

上面我们使用以避免必须评估默认值表达式,除非需要 - 这可以帮助提高重度操作的性能,并降低意外副作用的风险。有关更多信息,请查看“在设计Swift API时使用@autoclosure”。

使用我们的新下标变体,我们现在可以轻松地执行诸如将元素附加到存储在其中的数组之类的操作,或者根据需要创建新数组- 所有这些都在一行代码中:

同样,我们必须提供足够的上下文和措辞,以明确我们的订阅API所做的事情,遵循相同的约定,在这方面肯定有帮助,因为任何熟悉该订阅API的人都很有可能理解我们要做的事情对于上述。

静态下标

最后,让我们看一下作为Swift 5.1的一部分引入的新特性 - 静态下标 - 它与实例下标的工作方式大致相同,只是它们使我们能够直接对类型本身下标。

例如,我们可以使用这个新功能来提供专用类型来访问调用工具或脚本时传递的命令行参数和环境变量:

由于上述两个数据在程序中具有内在的通用性,因此只需通过下载我们的新类型和类型,就可以非常方便地访问它们而不必担心传递实例- 如下所示:

虽然能够下标类型非常酷,但重要的是不要将特定于上下文的数据放在静态上下文中,因为这样做会大大降低代码中的可测试性和关注点分离 - 这与单身人士经常遇到的问题相同原因。

结论

是什么让Swift的许多功能 - 包括下标 - 如此强大,不仅仅是将有限数量的用例硬编码到编译器或标准库中,任何类型都可以采用它们。

特别是在构建自定义集合或使用任何其他值组时,使用下标可以让我们设计真正简洁和轻量级的API。但是,仔细考虑基于下标的API是否在每种给定情况下提供足够的上下文非常重要 - 如果不是,则方法可能是更好的选择。

原文地址 https://www.swiftbysundell.com/posts/the-power-of-subscripts-in-swift

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190821A0331700?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券