关于 Swift 演变的趣味探讨

做者:Erica Sadun,原文连接,原文日期:2015/12/15
译者:小袋子;校对:Cee;定稿:numbbbbbgit

记得我曾分享过一些想法和建议,好比:github

newtype

一个是建议 Swift 推出一个 newtype 的关键词,它能够添加彻底不一样于原生的可扩展的派生类型。例如:swift

newtype Currency = NSDecimal

这建立了一个拥有全部 NSDecimal 全部行为的 Currency 类型。然而,你不能让一个 NSDecimal 类型的元素和一个 Currency 类型的元素相加,由于 Swift 中有类型检测。此外,你也能够扩展 Currency 类型。这样看起来就更加有针对性,由于不须要子类化或者添加新的存储属性。函数

newtype 的另外一个特性是可以建立柯里化类型:性能

newtype Counter<A> = Dictionary<A, Int>

类型是部分肯定的,具体行为能够在扩展中实现,从而能包含键(key)类型不相同但值类型都是 Int 的字典。测试

期待看到大家的评论。翻译

self

另一个提议是将 self 做为强制前缀,取代上下文语境推断。Greg Parker 在回复中写道:debug

在 Objective-C 中 self.property 这种写法很不优雅。设计

第一种方法是只使用 property。可是同名变量(ivar)会产生歧义,Swift 没有这样的问题。rest

第二种方法是用 property 访问属性,用 self->ivar 去访问同名变量。这是不可行的,由于会和现有的大量代码冲突。Swift 也没有这样的问题。

前置条件与断言(Precondition vs Assert)

Dave Abrahams 提出了一个有关重命名断言和前置条件的建议,我马上将其中的一些深入看法记在笔记本上:

从语言设计层面来讲,这两个函数扮演不一样的角色:
– assert:检查内部的错误代码。
– precondition:检查客户端给你的参数是否有效。

二者的区别很大,第二个要求有公共文档,第一个不须要。

例如:在 Swift 的标准库中,咱们保证永远不会出现内存错误,除非你调用 (Obj)C 代码或者使用一个明确地标着「unsafe」的结构。咱们须要去检验客户端参数,为了不给了非法的参数引发内存泄露,咱们要在参数中文档化这些需求做为前置条件,而且使用(等价的)precondition() 去检验它。咱们还有一系列的内部合理检查,用以肯定咱们代码假定的正确性,而类型系统还不能保证这个代码的假定。因为这些缘由,咱们使用(等价的)assert(),由于咱们不想下降你的代码性能(使用合理的检查)。

下面是几个具体的例子:

/// 一个集合,其中的元素类型为 Element

  public struct Repeat<Element> : CollectionType {
    ...
    /// 获取 `position` 位置的元素
    ///
    /// - 要求: `position` 是 `self` 中的有效位置而且 `position != endIndex`.
    public subscript(position: Int) -> Element {
      _precondition(position >= 0 && position < count, "Index out of range")
      return repeatedValue
    }
  }
  extension String.UTF8View {
    ...
   private func _encodeSomeContiguousUTF16AsUTF8(i: Int) -> (Int, UTF8Chunk) {
      _sanityCheck(elementWidth == 2)
      _sanityCheck(!_baseAddress._isNull)
   
      let storage = UnsafeBufferPointer(start: startUTF16, count: self.count)
      return _transcodeSomeUTF16AsUTF8(storage, i)
    }
  }

在第一个例子中,咱们有一个判断客户的 collection 没有越界的前置条件。在这个例子中,咱们其实能够不作检查,由于越界也不会致使内存错误(由于返回的都是同一个 repeatedValue),可是咱们仍是加上了这个检查,这样咱们的用户能够快速发现他们的 bug 。

第二个例子中是一个私有函数,它只能在咱们保证 elementWidth == 2 和 _baseAddress 不为 null 的条件下调用(_sanityCheck 在 stdlib 下等价于 assert)。由于这是私有函数,使用者就是咱们本身,因此看起来这个检查能够省略。可是有时候会出意外,好比后续的开发者可能会错误地使用它,所以咱们须要添加检查。由于咱们在 debug 和 release 的环境下运行咱们的测试,而且有较高的测试覆盖率,所以(若是错误使用函数)断言极可能在某处被触发。

读完上面的内容,你可能认为 assert() 只能在私有方法中使用,而 precondition() 只能在公共方法中使用。事实并不是如此;你能够内联任何私有方法到继承的公有方法的方法体内,所以合理的检查依然有意义。前置条件检查也会偶尔在私有方法中使用,最简单的例子就是公有方法转私有方法,复制代码的时候能够把原来的前置条件检查提取成一个私有的辅助方法(Helper)。

*注意,有些前置条件实际上不会被执行,因此你不能期望全部的前置条件都被执行。

本文由 SwiftGG 翻译组翻译,已经得到做者翻译受权,最新文章请访问 http://swift.gg

相关文章
相关标签/搜索