Swift API 设计指南(下)

875 阅读1分钟
原文链接: www.jianshu.com
  • 在 API 中给闭包参数和元组成员加上标签
    这些名字有解释说明的作用,可以出现在文档注释中,并且给元组成员一个形象的入口。

    /// Ensure that we hold uniquely-referenced storage for at least
    /// `requestedCapacity` elements.
    ///
    /// If more storage is needed, `allocate` is called with
    /// `byteCount` equal to the number of maximally-aligned
    /// bytes to allocate.
    ///
    /// - 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
    ) -> (reallocated: Bool, capacityChanged: Bool)

    用在闭包中时,虽然从技术上来说它们是参数标签,但你应该把它们当做参数名来选择和解释(文档中)。闭包在方法体中被调用时跟调用方法时是一致的,方法签名从一个不包含第一个参数的方法名开始:

    allocate(byteCount: newCount * elementSize)
  • 要特别注意那些不受约束的类型(譬如,AnyAnyObject和一些不受约束的范型参数),以防在重载时产生歧义。
    譬如,考虑如下重载:

    struct Array {
      /// Inserts `newElement` at `self.endIndex`.
      public mutating func append(newElement: Element)
    
      /// Inserts the contents of `newElements`, in order, at
      /// `self.endIndex`.
      public mutating func append<
        S : SequenceType where S.Generator.Element == Element
      >(newElements: S)
    }

    这些方法组成了一个语义族(semantic family),第一个参数的类型是明确的。但是当ElementAny时,一个单独的元素和一个元素集合的类型是一样的。

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

    为了避免歧义,让第二个重载方法的命名更加明确。

    struct Array {
      /// Inserts `newElement` at `self.endIndex`.
      public mutating func append(newElement: Element)
    
      /// Inserts the contents of `newElements`, in order, at
      /// `self.endIndex`.
      public mutating func append<
        S : SequenceType where S.Generator.Element == Element
      >(contentsOf newElements: S)
    }

    注意新命名是怎样更好地匹配文档注释的。在这种情况下,写文档注释时实际上也在提醒 API 作者自己注意问题。