你一定不知道Swift源碼怎么看?

我想你一定是在開玩笑。
源碼怎么看,打開看唄!說這話的時候請收下我的輕蔑,哈哈。不過就這個問題我今天在知乎搜索了一通。不要問我為什么在知乎搜索,鬼知道知乎什么都有。
那么,請收下我的提問:

如何閱讀Swift源碼

知乎果然沒有讓我失望,結(jié)果教程如下;

# 如何閱讀 Swift 標準庫中的源碼

順便提一下,這次搜索還讓我發(fā)現(xiàn)了一個比較不錯的swift網(wǎng)站,有心的同學(xué)請收下:swift.gg

于是今天搞了下源碼的編譯,并了解到一個叫做 GYB 的東西,這個東西今天先放一下。源碼編譯的過程無非就是用 brew 下了一些命令行軟件,然後使用 build 腳本跑一下過程,在此也不多說。但是今天的重點當(dāng)然是我們要從源碼出發(fā)搞一些事情。
續(xù):今天又build,發(fā)現(xiàn)也并沒有得出什么重要的東西,只是把gyb文件生成為swift文件,其他過程不知道它經(jīng)歷了什么,對我想看源碼沒有任何作用,還跑了整整一個下午;對于只是想看代碼的同學(xué),還是用官網(wǎng)給出的gyb.py腳本做處理吧;

  1. hashable

前兩天寫Dictionary時發(fā)現(xiàn)想用枚舉做key,自定義一個Dictionary,value是#selector,但是在寫的過程中發(fā)現(xiàn)說key值需要遵循h(huán)ashable協(xié)議??梢钥丛创a來理解一下。
首先要找到Hashable文件,發(fā)現(xiàn)swift的標準核心庫被放在 stdlib/public/core 下,有一個 Hashable.swift 文件,打開文件先是一大段的描述,大體內(nèi)容就是hashable協(xié)議作用的場景,以及給出了一個小例子;

一個Hash類型,提供了一個 hashValue 的屬性,它是一個整型常量, 如果有兩個相同類型的a,b,如果 a == b,那么 a.hashValue == b.hashValue;但是反過來,如果兩個hash值相同,并不表示a 就一定等于 b;
還有一點非常重要,就是在兩次不同的程序執(zhí)行中hash值并不保證相等,所以不要把hash值用在你的程序中;
Hashable協(xié)議可用于struct, enum, class,它繼承于 Equatable,所以遵循Hashable協(xié)議需要同時實現(xiàn)Hashable協(xié)議方法,以及 Equatable 協(xié)議方法;

/// A point in an x-y coordinate system.
    struct GridPoint {
        var x: Int
        var y: Int
    }

     extension GridPoint: Hashable {
         var hashValue: Int {
            return x.hashValue ^ y.hashValue &* 16777619
        }

        static func == (lhs: GridPoint, rhs: GridPoint) -> Bool {
            return lhs.x == rhs.x && lhs.y == rhs.y
        }
    }

       var tappedPoints: Set = [GridPoint(x: 2, y: 3), GridPoint(x: 4, y: 1)]
       let nextTap = GridPoint(x: 0, y: 1)
       if tappedPoints.contains(nextTap) {
          print("Already tapped at (\(nextTap.x), \(nextTap.y)).")
       } else {
          tappedPoints.insert(nextTap)
          print("New tap detected at (\(nextTap.x), \(nextTap.y)).")
       }
      // Prints "New tap detected at (0, 1).")

在實現(xiàn)的代碼里有一些奇怪的符號,暫時還有點摸不清頭腦,有些是一些編譯符號,大體能看懂點意思,但有些像@_silgen_name("_swift_stdlib_Hashable_isEqual_indirect")就完全看不懂,回頭找人再請教;
這里還要說的一個就是一個UnsafePointer<T>:

在 Swift 中,指針都使用一個特殊的類型來表示,那就是 UnsafePointer<T>。遵循了 Cocoa 的一貫不可變原則,UnsafePointer<T> 也是不可變的。當(dāng)然對應(yīng)地,它還有一個可變變體,UnsafeMutablePointer<T>。絕大部分時間里,C 中的指針都會被以這兩種類型引入到 Swift 中:C 中 const 修飾的指針對應(yīng) UnsafePointer (最常見的應(yīng)該就是 C 字符串的 const char * 了),而其他可變的指針則對應(yīng) UnsafeMutablePointer。除此之外,Swift 中存在表示一組連續(xù)數(shù)據(jù)指針的 UnsafeBufferPointer<T>,表示非完整結(jié)構(gòu)的不透明指針 COpaquePointer 等等。另外你可能已經(jīng)注意到了,能夠確定指向內(nèi)容的指針類型都是泛型的 struct,我們可以通過這個泛型來對指針指向的類型進行約束以提供一定安全性。

需要具體了解的看這篇:UnsafePointe<T>

順便吐槽句哈,apple的代碼也還有這種東西,也不知道是修改過的沒有;


FIXME
  1. Equatable
  • 它是一種可用于值比較的類型;
  • 在序列和集合操作中,可以將一個遵循了Equatable協(xié)議的對象傳遞給contaions(_:)方法,來確定是否包含,用法如下:
let students = ["Nora", "Fern", "Ryan", "Rainer"]

let nameToCheck = "Ryan"
if students.contains(nameToCheck) {
    print("\(nameToCheck) is signed up!")
} else {
    print("No record of \(nameToCheck).")
}
   // Prints "Ryan is signed up!"

/// Conforming to the Equatable Protocol
=
  • 本地類型繼承自Equatable協(xié)議需要注意:
    1. 對于一個struct類型,它的所有存儲屬性都需要遵循Equatable協(xié)議;
    2. 對于一個enum類型,它的所有關(guān)聯(lián)值都需要遵循Equatable協(xié)議;
    3. 如果上述標準不符合,需要在擴展中實現(xiàn)==靜態(tài)方法;
      例如:
class StreetAddress {
    let number: String
    let street: String
    let unit: String?
    init(_ number: String, _ street: String, unit: String? = nil) {
        self.number = number
        self.street = street
        self.unit = unit
    }
}

extension StreetAddress: Equatable {
    static func == (lhs: StreetAddress, rhs: StreetAddress) -> Bool {
        return
            lhs.number == rhs.number &&
            lhs.street == rhs.street &&
            lhs.unit == rhs.unit
    }
}

let addresses = [StreetAddress("1490", "Grove Street"),
                 StreetAddress("2119", "Maple Avenue"),
                 StreetAddress("1400", "16th Street")]
let home = StreetAddress("1400", "16th Street")
print(addresses[0] == home)
// Prints "false"
print(addresses.contains(home))
// Prints "true"
  • 另外我在這個實現(xiàn)里面看到了以前數(shù)學(xué)課知識的身影:
  • a == a is always true (Reflexivity) # 自反性
  • a == b implies b == a (Symmetry) # 對稱性
  • a == b and b == c implies a == c (Transitivity) # 傳遞性
    所以我們定義的==(兩對象相等)完全取決于我們自己實現(xiàn)的靜態(tài)方法:
class IntegerRef: Equatable {
    let value: Int
    init(_ value: Int) {
        self.value = value
    }
    static func == (lhs: IntegerRef, rhs: IntegerRef) -> Bool {
        return lhs.value == rhs.value
    }
}
let a = IntegerRef(100)
let b = IntegerRef(100)
print(a == a, a == b, separator: ", ")
// Prints "true, true"

而不相等的定義則完全是,自實現(xiàn)的相等操作取反:

extension Equatable {
  /// Returns a Boolean value indicating whether two values are not equal.
  ///
  /// Inequality is the inverse of equality. For any values `a` and `b`, `a != b`
  /// implies that `a == b` is `false`.
  ///
  /// This is the default implementation of the not-equal-to operator (`!=`)
  /// for any type that conforms to `Equatable`.
  ///
  /// - Parameters:
  ///   - lhs: A value to compare.
  ///   - rhs: Another value to compare.
  @inlinable // FIXME(sil-serialize-all)
  @_transparent
  public static func != (lhs: Self, rhs: Self) -> Bool {
    return !(lhs == rhs)
  }
}

這個實現(xiàn)是已經(jīng)定義好的!!!

  • =====的區(qū)別
    看一下這兩者的區(qū)別:
public protocol Equatable {
  /// Returns a Boolean value indicating whether two values are equal.
  ///
  /// Equality is the inverse of inequality. For any values `a` and `b`,
  /// `a == b` implies that `a != b` is `false`.
  ///
  /// - Parameters:
  ///   - lhs: A value to compare.
  ///   - rhs: Another value to compare.
  static func == (lhs: Self, rhs: Self) -> Bool
}
@inlinable // FIXME(sil-serialize-all)
public func === (lhs: AnyObject?, rhs: AnyObject?) -> Bool {
  switch (lhs, rhs) {
  case let (l?, r?):
    return ObjectIdentifier(l) == ObjectIdentifier(r)
  case (nil, nil):
    return true
  default:
    return false
  }
}

從以上可以看出,==只是由實現(xiàn)好的靜態(tài)函數(shù)決定,而===則是可以判斷兩個對象是否完全相等,這有點像判斷兩個指針相等一樣,同樣,我們要注意,如果兩個可選對象都是nil,則也是===的;

  1. 搞清楚兩個問題
  • UTC 與 GMT
    UTC(Coordinated Universal Time)標準時間參照,協(xié)調(diào)時間時,世界標準時間;
    GMT(Greenwich Mean Time)時區(qū),即格林尼治時間,位于本初子午線的標界處時間,世界計算時間和經(jīng)度的起點,GMT是個時區(qū),等同于世界時,所以GMT = UTC + 0,我們國家所在時間均以北京時間計算,北京位于東八區(qū),所以時區(qū)為GMT + 8;
  • Locale
    網(wǎng)上找了一圈,最后還是swift源碼文檔里給出的解釋最靠譜:Locale封裝了有關(guān)語言,文化和技術(shù)規(guī)范和標準的信息。由語言環(huán)境封裝的信息示例包括,用于數(shù)字中小數(shù)點分隔符的符號以及格式化日期的方式。區(qū)域設(shè)置通常用于根據(jù)用戶的習(xí)俗和偏好提供,格式化和解釋信息。它們經(jīng)常與格式化程序一起使用。雖然可以使用很多語言環(huán)境,但通常使用與當(dāng)前用戶關(guān)聯(lián)的語言環(huán)境。
    語言環(huán)境跟系統(tǒng)的環(huán)境設(shè)置有關(guān),會涉及到操作系統(tǒng)語言環(huán)境設(shè)置,個人理解就是一個國際化的東西。
    區(qū)域設(shè)置中的概念 LANGID & LCID:
    LANGID & LCID
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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