探索Swift标准库源代码

您是否发现本身没法理解框架或库,并但愿您能看到源代码?Apple没有共享源代码,UIKit但若是您正在努力理解的方法是Swift标准库的一部分,那么您很幸运。git

访问GitHub存储库

Apple在公共GitHub存储库中发布Swift编程语言的源代码,包括标准库:github

您可能会发如今GitHub上浏览存储库已足以快速查看但我喜欢克隆并下载本地副本:编程

$ mkdir swift-source
$ cd swift-source/
$ git clone https://github.com/apple/swift.git
Cloning into 'swift'...
remote: Enumerating objects: 915646, done.
remote: Total 915646 (delta 0), reused 0 (delta 0), pack-reused 915646
Receiving objects: 100% (915646/915646), 415.74 MiB | 6.42 MiB/s, done.
Resolving deltas: 100% (742664/742664), done.
Checking out files: 100% (16802/16802), done.

复制代码

您能够将swift文件夹放入Xcode项目中进行浏览,但这会使个人Mac旋转沙滩球几分钟。我更喜欢用BBEdit打开文件夹,它既快又有更好的多文件搜索工具。swift

Swift repo文件夹层次结构

您将在core子目录中找到标准库的源代码:bash

$ cd swift/stdlib/public/core

复制代码

值得花时间浏览源代码。我发现它有很好的记录和信息。让咱们看一个源代码有助于咱们理解的示例。app

一个问题 String

我最近写了关于在Swift中测试空字符串的文章。在那篇文章中,我声称你应该使用isEmpty而不是count避免迭代整个字符串。一位读者问我这是否是真的?个人说法来自String文件:框架

要检查字符串是否为空,请使用其isEmpty属性,而不是将其中一个视图的长度与0进行比较。与isEmpty不一样,计算视图的count属性须要迭代字符串的元素。dom

咱们能比信任文档更好吗?咱们可使用标准库源代码来查看字符串的工做方式isEmptycount工做方式吗?编程语言

StringCharacterView

在标准库源代码中查找的位置并不老是很明显。搜索core目录最终会带您到正确的地方,但也能够带走一些兔子洞。有一个String.swift文件,但它不包含任何一个isEmptycount工具

回想一下个人Swift String备忘单,您可能还记得Swift 4将字符串的默认视图设置为一组字符。目录中有一个StringCharacterView.swift文件core扩展String为采用BidirectionalCollection协议:

// StringCharacterView.swift
extension String: BidirectionalCollection {

复制代码

StringCharacterView没有定义isEmpty,但咱们发现count

public var count: Int {
    return distance(from: startIndex, to: endIndex)
  }

复制代码

distance方法调用咱们仍须要查找的内部方法,但它是一个开始:

public func distance(from start: Index, to end: Index) -> IndexDistance {
    return _distance(from: start, to: end)
  }

复制代码

BidirectionalCollection

双向集合扩展了集合,以在集合上添加向后遍历:

// BidirectionalCollection.swift
public protocol BidirectionalCollection: Collection
where SubSequence: BidirectionalCollection, Indices:
BidirectionalCollection {

复制代码

这是咱们找到实现的地方,_distance而且能够看到它对集合进行迭代(向前或向后):

internal func _distance(from start: Index, to end: Index) -> Int {
  var start = start
  var count = 0

  if start < end {
    while start != end {
      count += 1
      formIndex(after: &start)
    }
  }
  else if start > end {
    while start != end {
      count -= 1
      formIndex(before: &start)
    }
  }

  return count
}

复制代码

让咱们继续前进,看看可否找到isEmpty

采集

Collection协议的基础上Sequence,并增长了startIndexendIndex朋友与咱们共同的属性isEmptycount

// Collection.swift (details omitted)
public protocol Collection: Sequence {

  var startIndex: Index { get }
  var endIndex: Index { get }

  var isEmpty: Bool { get }
  var count: Int { get }

复制代码

源代码中的注释为咱们提供了更多提示:

对于不符合的集合RandomAccessCollection,访问该count属性会迭代集合的元素。

由于count有这个警告:

复杂性:O(1)若是集合符合RandomAccessCollection; 不然,O(n),其中n是集合的长度。

评论确认了咱们的理解,String但也告诉咱们为何会这样。重要的是该系列是否符合RandomAccessCollection。相似的类型Array容许随机访问,但String不容许。有关完整列表,请参阅RandomAccessCollection

Collection.swift文件的下方,咱们找到了一个协议扩展,它最终为咱们提供了如下的默认实现isEmpty

public var isEmpty: Bool {
  return startIndex == endIndex
}

复制代码

因此对于a String,咱们最好isEmpty不要使用而不是count


转载自:www.jianshu.com/p/dfab3739c…

相关文章
相关标签/搜索