Swift 官方API設(shè)計指南(翻譯)

原文鏈接:https://swift.org/documentation/api-design-guidelines/

基本原則

  • 代碼明晰是你主要目標(biāo)。實體諸如方法和屬性,一次聲明,往往會被使用多次。故設(shè)計APIs時盡量使之清晰并且簡練。評估某個API設(shè)計是否合理,單從閱讀其聲明并不足以下結(jié)論,往往需要在真實示例下,才能確保它在上下文中是清晰正確的。

  • 明晰優(yōu)先于簡練。盡管Swift代碼可以書寫的非常緊湊簡練,但實現(xiàn)最少代碼量并非是我們的目標(biāo)。Swift代碼的簡練,只是強(qiáng)類型系統(tǒng)和自然降低功能樣板產(chǎn)生的附加效果而已。

  • 為每個聲明書寫文檔注釋。通過書寫文檔獲得的經(jīng)驗見解會對你的設(shè)計產(chǎn)生深遠(yuǎn)的影響,所以不要忽視之。

    如果你無法使用簡潔的術(shù)語描述你的APIs功能,那么你可能設(shè)計了錯誤的APIs。

詳情
  • 使用Swift的Markdown語法。

  • 以摘要開始,描述聲明實體的功能。一般的,通過其聲明和摘要信息,API會被人清晰的理解。

    /// Returns `self`的"view"逆向集合。即包含相同元素,但順序相反。
         func reversed() -> ReverseCollection
    
    • 專注于摘要:這是最為重要的部分。很多優(yōu)秀的文檔注釋只包含一個優(yōu)質(zhì)的摘要,別無它物。

    • 盡可能使用單句片段,并以句點(diǎn)結(jié)束。不要使用完整冗長的句子。

    • 描述方法或函數(shù)的功能和返回值,忽略無意義的null功能和Viod返回:

    /// 在self起始處插入 newHead 。
    mutating func prepend(_ newHead: Int)
    /// 返回一個包含head并由self跟隨的列表。func prepending(_ head: Element) -> List
    /// 若self非空,刪除并返回第一個元素;
    /// 否則返回nil。
    mutating func popFirst() -> Element?
    ```
    提示:在極少數(shù)情況下,如上面的popFirst,摘要是由分號分隔的多個句子片段組成。

    • 下標(biāo)注釋:即描述下標(biāo)訪問的內(nèi)容:

      /// 訪問下標(biāo)為 第`index`個的元素。
                subscript(index: Int) -> Element { get set }
      
    • 構(gòu)造方法:即描述初始化方法創(chuàng)建的內(nèi)容:

      /// 創(chuàng)建實例:該實例中包含n個`x`。
                init(count n: Int, repeatedElement x: Element)
      
    • 其它聲明類場景,所聲明的實體務(wù)必描述清晰。

      /// 集合對象:在任何位置均支持同等高效的插入、刪除操作。
                struct List {
                  /// `self`非空,`self`的首個元素;
                  ///否則,返回`nil`。
                    var first: Element?
              ...
      
  • (可選),連續(xù)使用一個或多個段落和項目符號項。段落用空行分隔并使用完整的句子。

    /// 將`items`中每個元素的文本表示,執(zhí)行標(biāo)準(zhǔn)輸出。   ← 摘要
        ///                                              ← 空行
        /// 每個元素`x`的文本表示均由`String(x)`表達(dá)式生成 ← 補(bǔ)充說明
        ///
        /// - 參數(shù) separator: 元素之間的打印文本。           ?
        /// - 參數(shù) terminator: 結(jié)尾打印的文本               ? 參數(shù)部分
        ///                                              ?
        /// - 備注: 若不要在結(jié)尾新起一行,
        ///則置`terminator: ""`即可。                      ?
        ///- 其它關(guān)聯(lián): `CustomDebugStringConvertible`,     ? 命令符號
        ///   `CustomStringConvertible`, `debugPrint`.   ?
          public func print(
                _ items: Any..., separator: String = " ", terminator: String = "\n")
    

    流行的IDE工具(如Xcode)對以下關(guān)鍵字開頭的項目符號進(jìn)行了特殊的處理:

    |關(guān)鍵字|||
    |:--:|:--:|:--:|:--:|
    |Attention|Author|Authors|Bug|
    |Complexity|Copyright|Date|Experiment|
    |Important|Invariant|Note|Parameter|
    |Parameters|Postcondition|Precondition|Remark|
    |Requires|Returns|SeeAlso|Since|
    |Throws|ToDo|Version|Warning|

命名

提高明晰方法
  • 為了便于閱讀代碼,在進(jìn)行命名時,要涵蓋所有必須的單詞,以避免歧義。

    例如,一個方法:在集合中刪除給定位置的元素。

    code1:?
    extension List {
          public mutating func remove(at position: Index) -> Element
        }
    employees.remove(at: x)
    

    如果我們從方法簽名中省略單詞at,則可能使讀者認(rèn)為該方法是用于搜索并刪除等于x的元素,而不是使用x來指示要刪除的元素的位置。

    code2:?
    employees.remove(x) // 不清晰:是刪除x嗎?
    
  • 務(wù)必忽略不必須的單詞。命名中的每個單詞都應(yīng)在使用場景中傳達(dá)重要的信息。

    有時需要更多的單詞來闡明意圖或消除歧義,但應(yīng)省略那些眾所周知的冗余詞。特別是要省略那些僅為重復(fù)類型信息的單詞。

    code:?
    public mutating func removeElement(_ member: Element) -> Element?
        allViews.removeElement(cancelButton)
    

    在該示例中,Element在調(diào)用場景中沒有傳達(dá)任何重要信息,故該API可優(yōu)化為:

    code:?
    public mutating func remove(_ member: Element) -> Element?
        allViews.remove(cancelButton) // clearer
    

    有時,重復(fù)類型信息對于避免歧義是有必要的。但通常而言,最好使用描述參數(shù)角色而不是其類型的單詞。有關(guān)詳細(xì)信息,請參閱下一項。

  • 根據(jù)角色來命名變量,參數(shù)和關(guān)聯(lián)類型,而不是根據(jù)類型約束。

    code:?
    var string = "Hello"
          protocol ViewController {
              associatedtype ViewType : View
        }
      class ProductionLine {
        func restock(from widgetFactory: WidgetFactory)
        }
    

    以這種方式重新定位類型名稱無法優(yōu)化清晰度和表現(xiàn)力。相反,努力選擇一個表達(dá)實體角色的名稱反而更好。

    code: ?
    var greeting = "Hello"
        protocol ViewController {
            associatedtype ContentView : View
      }
    class ProductionLine {
        func restock(from supplier: WidgetFactory)
      }
    

    如果關(guān)聯(lián)類型與其協(xié)議約束緊密綁定以使協(xié)議名稱為角色,請通過將Protocol附加到協(xié)議名稱來避免沖突:

    protocol Sequence {
          associatedtype Iterator : IteratorProtocol
        }
        protocol IteratorProtocol { ... }
    
  • 補(bǔ)償弱類型信息以闡明參數(shù)的作用。

    尤其當(dāng)參數(shù)類型是NSObject,Any,AnyObject或諸如Int或String的基本類型時,類型信息和在使用處的上下文可能無法完全傳達(dá)意圖。 在此示例中,聲明可能是明確的,但使用點(diǎn)是模糊的:

    code:?
    func add(_ observer: NSObject, for keyPath: String)
        grid.add(self, for: graphics) // 模糊
    

    為了恢復(fù)清晰度,在每個弱類型參數(shù)前面加上描述其角色的名詞:

    code:?
    func addObserver(_ observer: NSObject, forKeyPath path: String)
          grid.addObserver(self, forKeyPath: graphics) // 清晰
    
力求流暢使用
  • 使用標(biāo)準(zhǔn)英語語法規(guī)則來命名方法和函數(shù)。

    code: ?
    x.insert(y, at: z)          “x, insert y at z”
         x.subViews(havingColor: y)  “x's subviews having color y”
        x.capitalizingNouns()       “x, capitalizing nouns”
    
    code: ?
    x.insert(y, position: z)
        x.subViews(color: y)
        x.nounCapitalize()
    

    在第一個或第二個參數(shù)之后,當(dāng)這些參數(shù)不是調(diào)用方法的核心時,流利性降級是可以接受的。即如果不影響方法要表達(dá)的含義,那可以簡化第一個或者前兩個參數(shù),這樣使用起來更加流暢。

    AudioUnit.instantiate(
        with: description, 
        options: [.inProcess], completionHandler: stopProgressBar)
    
  • make前綴開始工廠方法的名稱命名。如 x.makeIterator()。

  • 構(gòu)造方法和工廠方法調(diào)用的第一個參數(shù)不應(yīng)該形成以基本名稱開頭的短語。如 x.makeWidget(cogCount: 47)。

    例如,這些調(diào)用方法的第一個參數(shù)不會作為與基本名稱相同的短語的一部分讀?。?/p>

    code: ?
    let foreground = Color(red: 32, green: 64, blue: 128)
        let newPart = factory.makeWidget(gears: 42, spindles: 14)
        let ref = Link(target: destination)
    

    在以下示例中,API作者嘗試使用第一個參數(shù)創(chuàng)建語法連續(xù)性:

    code: ?
    let foreground = Color(havingRGBValuesRed: 32, green: 64, andBlue: 128)
        let newPart = factory.makeWidget(havingGearCount: 42, andSpindleCount: 14)
        let ref = Link(to: destination)
    

    實際上,此準(zhǔn)則以及參數(shù)標(biāo)簽的準(zhǔn)則意味著第一個參數(shù)將具有標(biāo)簽,除非調(diào)用正在執(zhí)行值保留類型轉(zhuǎn)換。

    let rgbForeground = RGBColor(cmykForeground)
    
  • 根據(jù)副作用命名函數(shù)和方法。

    • 那些沒有副作用的函數(shù)和方法應(yīng)該讀作是一個名詞詞組。如x.distance(to: y), i.successor().

    • 那些有副作用的函數(shù)和方法應(yīng)該讀作是一個命令式的動詞短語。如print(x), x.sort(), x.append(y)。

    • 命名名稱一致的Mutating/nonmutating方法對。變異方法通常具有一個類似語義的非突變變體,但返回新值而不是就地更新實例。

      • 當(dāng)操作方法由動詞自然描述時,使用動詞對變異方法進(jìn)行命名,而應(yīng)用“ed”或“ing”后綴來命名對應(yīng)的其非變異方法。
      Mutating Nonmutating
      x.sort() z = x.sorted()
      x.append(y) z = x.appending(y)
   * 更傾向于使用[動詞的過去分詞](https://en.wikipedia.org/wiki/Participle)命名非變異變體(通常附加`ed`)

    ```
    /// 即刻逆向 `self`。
            mutating func reverse()
            /// 返回self的逆向拷貝。
            func reversed() -> Self
            ...
          x.reverse()
          let y = x.reversed()
    ```
    
    * 當(dāng)添加`ed`不具有語法性,因為動詞具有直接對象時,使用動詞的當(dāng)前分詞命名非變異變體,通過附加“ing”。(應(yīng)為語法問題)

    ```
    /// 過濾掉self中空行
            mutating func stripNewlines()
          /// 返回self的拷貝,該拷貝過濾掉了所有的空行。
          func strippingNewlines() -> String
          ...
        s.stripNewlines()
        let oneLine = t.strippingNewlines()
    ```
    
* 當(dāng)操作方法由名詞描述時,使用名詞作為非突變方法。并使用`form`前綴來命名其對應(yīng)的變異方法。

| Nonmutating | Mutating |
|:--:|:--:|
|x = y.union(z)| y.formUnion(z)|
|j = c.successor(i)|c.formSuccessor(&i)|
  • 當(dāng)使用非突變方法時,布爾方法和屬性的使用在接收者看來,應(yīng)為斷言的形式。如:x.isEmpty, line1.intersects(line2).
  • 描述類的協(xié)議應(yīng)該以名詞命名。如Collection
  • 功能類的協(xié)議應(yīng)以后綴為able,ibleing的單詞命名。如Equatable, ProgressReporting。
  • 其它類型,諸如屬性、變量、常量應(yīng)以名詞來命名。
更好的使用術(shù)語

名詞 - 在特定領(lǐng)域或?qū)I(yè)中具有精確、專門意義的詞或短語。

  • 如果一個更常見的詞語同樣傳達(dá)了相同意義,則避免使用模糊術(shù)語 。如果皮膚能夠闡述您的目的,請不要說表皮。藝術(shù)品是一種必不可少的溝通工具,但只應(yīng)用于捕捉原本會丟失的重要意義。

  • 如果您使用藝術(shù)術(shù)語,請堅持使用它既定的意義

    使用技術(shù)術(shù)語而不是更常見的單詞,其唯一原因是它可以更精確地表達(dá)一些本來會模棱兩可或不清楚的東西。因此,API應(yīng)嚴(yán)格使用術(shù)語。

    • 勿使專家驚訝。如果我們?yōu)楸娝苤男g(shù)語發(fā)明了新的含義,任何已經(jīng)熟悉它的人都會感到驚訝或憤怒。
    • 不要迷惑初學(xué)者:任何試圖學(xué)習(xí)該術(shù)語的人都可能會進(jìn)行網(wǎng)絡(luò)搜索并找到其傳統(tǒng)的原始意義。
  • 避免使用縮寫??s寫,尤其是非標(biāo)準(zhǔn)的縮寫,實際上是術(shù)語,因為理解依賴于正確地將它們翻譯成非縮寫形式。

    您使用的任何縮寫的含義,都可在網(wǎng)絡(luò)找到。即眾所周知的含義。

  • 擁抱先例。不要以犧牲與現(xiàn)有文化的一致性為代價來為初學(xué)者優(yōu)化術(shù)語。

    命名連續(xù)數(shù)據(jù)結(jié)構(gòu)為Array比使用簡單術(shù)語(如List)更好,即使初學(xué)者可能更容易理解List的含義。 Array是現(xiàn)代計算的基礎(chǔ),因此每個程序員都應(yīng)該知道 - 或者很快就會學(xué)到 - Array的概念。 使用大多數(shù)程序員都熟悉的術(shù)語,他們的問題搜索將很快得到解決。

    在特定的編程域中,例如數(shù)學(xué),諸如sin(x)之類的廣泛使用的術(shù)語,要優(yōu)于諸如verticalPositionOnUnitCircleAtOriginOfEndOfRadiusWithAngle(x)的解釋性短語。 請注意,在這種情況下,先例超過了指南中避免縮寫的規(guī)定:雖然完整的單詞是sine,但是sin(x)在程序員中已經(jīng)普遍使用了幾十年,并且在幾個世紀(jì)的數(shù)學(xué)家中也是如此。

代碼規(guī)范

通用規(guī)范
  • 任何復(fù)雜度不是O(1)的計算屬性,均要注釋。人們通常認(rèn)為屬性訪問不涉及重要的計算,因為他們在心理上將屬性作為存儲類型了。當(dāng)一反常態(tài)時,需要備注提醒。

  • 首選方法和屬性實現(xiàn)而非函數(shù)。自由函數(shù)僅在以下特例中使用:

    1. 無顯式self:

      min(x,y,z)

    2. 函數(shù)是無約束的泛型時:

      print(x)

    3. 函數(shù)語法是已建立的域表示法的一部分時:

      sin(x)

  • 命名規(guī)范:類型和協(xié)議的命名遵循大駝峰命名法,其他一切都遵循小駝峰命名法。

    縮略語和首字母縮略詞:通常在美式英語中顯示為大寫.應(yīng)根據(jù)拼寫規(guī)范統(tǒng)一大寫或小寫。

    var utf8Bytes: [UTF8.CodeUnit]
        var isRepresentableAsASCII = true
        var userSMTPServer: SecureSMTPServer
    

    其他首字母縮略詞應(yīng)視為普通詞:

    var radarDetector: RadarScanner
        var enjoysScubaDiving = true
    
  • 當(dāng)方法具有相同的基本含義或在不同的域中操作時,方法可以共用基本名稱。

    例如,以下方案值得推薦,因為這些方法的功能基本上是相同的:

    code: ?
    extension Shape {
        /// 返回 `true` ,假如 `other` 點(diǎn)在`self`面積之內(nèi).
        func contains(_ other: Point) -> Bool { ... }
    
        /// 返回 `true` 假如 `other` 圖形完全在 `self`之內(nèi).
        func contains(_ other: Shape) -> Bool { ... }
    
        /// 返回 `true` 假如 `other`線條在 `self`之內(nèi).
      func contains(_ other: LineSegment) -> Bool { ... }
      }
    

    由于幾何類型和集合是不同的域,因此在同一程序中也可以:

    code: ?
    extension Collection where Element : Equatable {
        /// 返回 `true` 假如 `self` 包含一個同 `sought`相同的元素.
        func contains(_ sought: Element) -> Bool { ... }
      }
    

    當(dāng)然,這些索引方法具有不同的語義,并且應(yīng)該以不同的方式命名:

    code: ?
    extension Database {
        /// 重建數(shù)據(jù)庫的搜索索引
        func index() { ... }
    
        /// 返回給定表中的第n行
        func index(_ n: Int, inTable: TableID) -> TableRow { ... }
      }
    

    最后,避免“在返回類型上重載”,因為它會在存在類型推斷時引起歧義:

    code: ?
    extension Box {
          /// 返回存儲在`self`中的`Int`值,否則,返回`nil`
        func value() -> Int? { ... }
    
        /// 返回存儲在`self`中的`String `值,否則,返回`nil` 
        func value() -> String? { ... }
        }
    
參數(shù)

func move(from start: Point, to end: Point)

  • 選擇參數(shù)名稱以供文檔注釋。即使參數(shù)名稱沒有出現(xiàn)在函數(shù)或方法的使用點(diǎn),它們也起著重要的解釋作用。

    選擇這些名稱可以使文檔易于閱讀。例如,以下這些名稱使文檔閱讀理解更加自然:

    code: ?
    /// 返回滿足`predicate`斷言的,并包含`self`的元素集合 
        func filter(_ predicate: (Element) -> Bool) -> [Generator.Element]
        /// 以`newElements`替換給定 `subRange`范圍的集合。
        mutating func replaceRange(_ subRange: Range, with newElements: [E])
    

    當(dāng)然,以下例子使文檔變得笨拙和不合語法:

    code: ?
    /// 返回滿足`includedInResult `斷言的,并包含`self`的元素集合 .
        func filter(_ includedInResult: (Element) -> Bool) -> [Generator.Element]
        /// 以`with `替換給定 `r `范圍的集合。
        mutating func replaceRange(_ r: Range, with: [E])
    
  • 一般場景時,合理利用默認(rèn)參數(shù)。某一參數(shù)在大多數(shù)場景下都是某個固定值,比較適合設(shè)置默認(rèn)參數(shù)。

    默認(rèn)參數(shù)通過隱藏不相關(guān)的信息來提高可讀性。例如:

    code: ?
    let order = lastName.compare(
        royalFamilyName, options: [], range: nil, locale: nil)
    

    可以更為簡潔:

    let order = lastName.compare(royalFamilyName)
    

    默認(rèn)參數(shù)通常比使用方法集更可取,因為它們會降低理解API的認(rèn)知負(fù)擔(dān)。

    code: ?
    extension String {
        /// ...description...
        public func compare(
           _ other: String, options: CompareOptions = [],
           range: Range? = nil, locale: Locale? = nil
      ) -> Ordering
    }
    

    上述方案可能并不簡單,但相比方法集,足夠簡潔:

    code: ?
    extension String {
        /// ...description 1...
        public func compare(_ other: String) -> Ordering
        /// ...description 2...
        public func compare(_ other: String, options: CompareOptions) -> Ordering
        /// ...description 3...
      public func compare(
           _ other: String, options: CompareOptions, range: Range) -> Ordering
      /// ...description 4...
      public func compare(
         _ other: String, options: StringCompareOptions,
         range: Range, locale: Locale) -> Ordering
      }
    

    方法集合的每個成員都需要單獨(dú)的文檔注釋,并由用戶理解。用戶需要完全理解它們,才能選擇最優(yōu)方法。 偶爾也會出現(xiàn)令人驚訝的問題 - 例如,foo(bar:nil)foo()并不總是同等的 - 文檔繁瑣,差異卻微小。 使用含默認(rèn)值單一方法可提供極其優(yōu)越的編程體驗。

  • 默認(rèn)參數(shù)應(yīng)放置在參數(shù)列表的末尾。沒有默認(rèn)值的參數(shù)通常對于方法的語義更為重要,并且在調(diào)用方法時提供穩(wěn)定的初始使用模式。

參數(shù)標(biāo)簽

func move(from start: Point, to end: Point)

x.move(from: x, to: y)

  • 在無法有效區(qū)分參數(shù)時省略所有標(biāo)簽

    如:min(number1, number2),zip(sequence1, sequence2).

  • 在執(zhí)行值保留類型轉(zhuǎn)換的構(gòu)造器中,省略第一個參數(shù)標(biāo)簽。

    第一個參數(shù)應(yīng)該始終是轉(zhuǎn)換的來源:

    extension String {
        // 將`x`轉(zhuǎn)換為給定基數(shù)中的文本表示
      init(_ x: BigInt, radix: Int = 10)   ← Note the initial underscore
      }
      text = "The value is: "
      text += String(veryLargeNumber)
      text += " and in hexadecimal, it's"
      text += String(veryLargeNumber, radix: 16)
    

    但是,在“縮小”類型轉(zhuǎn)換中,添加描述縮小的標(biāo)簽是有必要的。

    extension UInt32 {
        /// Creates an instance having the specified `value`.
        init(_ value: Int16)            ← Widening, so no label
        /// 創(chuàng)建一個具有最低32位“source”的實例 `source`.
        init(truncating source: UInt64)
        /// 創(chuàng)建近似于`valueToApproximate`的實例 
        init(saturating valueToApproximate: UInt64)
      }
    

    值保持類型轉(zhuǎn)換單態(tài)的,即原始值的每個差異均會導(dǎo)致結(jié)果值的差異。 例如,從Int8到Int64的轉(zhuǎn)換是值保留的,因為每個不同的Int8值都轉(zhuǎn)換為不同的Int64值;但是,在相反方向上的轉(zhuǎn)換不能保留值:Int64具有比Int8中表示的值更多的可能值。

    注意:檢索原始值的能力與轉(zhuǎn)換是否有保留值無關(guān)。

  • 當(dāng)?shù)谝粋€參數(shù)構(gòu)成介詞短語的一部分時,給它設(shè)置一個參數(shù)標(biāo)簽。參數(shù)標(biāo)簽通常應(yīng)該從介詞開始,如x.removeBoxes(havingLength: 12)。

    當(dāng)前兩個參數(shù)表示單個抽象的一部分時會出現(xiàn)異常:

    code: ?
    a.move(toX: b, y: c)
        a.fade(fromRed: b, green: c, blue: d)
    

    這種情況,在介詞后添加參數(shù)標(biāo)簽,以保持抽象概念清晰。

    code: ?
    a.moveTo(x: b, y: c)
        a.fadeFrom(red: b, green: c, blue: d)
    
  • 否則,如果第一個參數(shù)構(gòu)成語法短語的一部分,則省略其標(biāo)簽.將前置的單詞附加到基本名稱上,例如, x.addSubview(y)
本指南認(rèn)為如果第一個參數(shù)不構(gòu)成語法短語的一部分,它應(yīng)該有一個標(biāo)簽。

```
?
view.dismiss(animated: false)
    let text = words.split(maxSplits: 12)
    let studentsByName = students.sorted(isOrderedBefore:                     
    Student.namePrecedes)
```

請注意,短語傳達(dá)正確的含義非常重要。以下可能表達(dá)會錯誤的觀點(diǎn)。

```
?
view.dismiss(false)   Don't dismiss? Dismiss a Bool?
    words.split(12)       Split the number 12?
```

另請注意,可以省略含默認(rèn)值的參數(shù)。在這種情況下,不要形成語法短語的一部分,因此它們應(yīng)始終具有標(biāo)簽。
  • 為其它所有參數(shù)添加參數(shù)標(biāo)簽。

特別說明

  • 在API中為tuple元組成員添加參數(shù)標(biāo)簽,命名閉包參數(shù)。

    這些名稱具有很好的解釋能力,可以從文檔注釋中引用,并提供對元組成員的訪問。

    /// 確保我們有requestedCapacity最后一個元素的唯一引用的存儲單元。 
        ///
        /// 如果需要更多存儲空間,則調(diào)用`allocate` 。且分配的字節(jié)數(shù)`bygerCount`等于最大數(shù)。
        ///
        /// - Returns:
        ///   - reallocated: `true` iff a new block of memory
      ///     was allocated.
      ///   - capacityChanged: `true` iff `capacity` was updated.
    mutating func ensureUniqueStorage(
        minimumCapacity requestedCapacity: Int, 
          allocate: (_ byteCount: Int) -> UnsafePointer<Void>
      ) -> (reallocated: Bool, capacityChanged: Bool)
    

    用于閉包參數(shù)的名稱,應(yīng)如頂級函數(shù)的參數(shù)名稱一樣。在閉包參數(shù)調(diào)用處不應(yīng)出現(xiàn)參數(shù)標(biāo)簽。

  • 使用不受約束的多態(tài)性(例如Any,AnyObject無約束的通用參數(shù))時要格外小心,以避免重載集中出現(xiàn)歧義。

    如考慮重載集:

    ?
    struct Array {
          ///  在 `self.endIndex`處插入`newElement`.
          public mutating func append(_ newElement: Element)
    
          /// 在`self.endIndex`順序插入 `newElements`內(nèi)容。
          public mutating func append(_ newElements: S)
            where S.Generator.Element == Element
        }
    

這些方法形成一個語義簇,并且參數(shù)類型明顯不同。但是,當(dāng)Element為Any時,單個元素可以與元素序列具有相同的類型。

```
?
var values: [Any] = [1, "a"]
    values.append([2, 3, 4]) // [1, "a", [2, 3, 4]] or [1, "a", 2, 3, 4]?
```

為消除歧義,可以更明確地命名第二個重載方法。

```
?
struct Array {
      /// 在 `self.endIndex`處插入`newElement`.
      public mutating func append(_ newElement: Element)

      /// 在`self.endIndex`順序插入 `newElements`內(nèi)容
      public mutating func append(contentsOf newElements: S)
        where S.Generator.Element == Element
    }
```

注:如何命名以更好地匹配文檔注釋。實際上是在編寫文檔注釋時,得到了API作者的注意。

更多

  • 紕漏之處,歡迎斧正。
  • 更多內(nèi)容請關(guān)注公眾號:IT互聯(lián)網(wǎng)自習(xí)室。
IT互聯(lián)網(wǎng)自習(xí)室.jpg
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容