關於 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

相關文章
相關標籤/搜索