程序员日常

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

2018-05-03  本文已影响7人  听风轻咛

我想你一定是在开玩笑。
源码怎么看,打开看呗!说这话的时候请收下我的轻蔑,哈哈。不过就这个问题我今天在知乎搜索了一通。不要问我为什么在知乎搜索,鬼知道知乎什么都有。
那么,请收下我的提问:

如何阅读Swift源码

知乎果然没有让我失望,结果教程如下;

# 如何阅读 Swift 标准库中的源码

顺便提一下,这次搜索还让我发现了一个比较不错的swift网站,有心的同学请收下:swift.gg

于是今天搞了下源码的编译,并了解到一个叫做 GYB 的东西,这个东西今天先放一下。源碼編譯的過程無非就是用 brew 下了一些命令行軟件,然後使用 build 腳本跑一下過程,在此也不多說。但是今天的重點當然是我們要從源碼出發搞一些事情。
续:今天又build,发现也并没有得出什么重要的东西,只是把gyb文件生成为swift文件,其他过程不知道它经历了什么,对我想看源码没有任何作用,还跑了整整一个下午;对于只是想看代码的同学,还是用官网给出的gyb.py脚本做处理吧;

  1. hashable

前两天写Dictionary时发现想用枚举做key,自定义一个Dictionary,value是#selector,但是在写的过程中发现说key值需要遵循hashable协议。可以看源码来理解一下。
首先要找到Hashable文件,发现swift的标准核心库被放在 stdlib/public/core 下,有一个 Hashable.swift 文件,打开文件先是一大段的描述,大体内容就是hashable协议作用的场景,以及给出了一个小例子;

一个Hash类型,提供了一个 hashValue 的属性,它是一个整型常量, 如果有两个相同类型的a,b,如果 a == b,那么 a.hashValue == b.hashValue;但是反过来,如果两个hash值相同,并不表示a 就一定等于 b;
还有一点非常重要,就是在两次不同的程序执行中hash值并不保证相等,所以不要把hash值用在你的程序中;
Hashable协议可用于struct, enum, class,它继承于 Equatable,所以遵循Hashable协议需要同时实现Hashable协议方法,以及 Equatable 协议方法;

/// 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).")

在实现的代码里有一些奇怪的符号,暂时还有点摸不清头脑,有些是一些编译符号,大体能看懂点意思,但有些像@_silgen_name("_swift_stdlib_Hashable_isEqual_indirect")就完全看不懂,回头找人再请教;
这里还要说的一个就是一个UnsafePointer<T>:

在 Swift 中,指针都使用一个特殊的类型来表示,那就是 UnsafePointer<T>。遵循了 Cocoa 的一贯不可变原则,UnsafePointer<T> 也是不可变的。当然对应地,它还有一个可变变体,UnsafeMutablePointer<T>。绝大部分时间里,C 中的指针都会被以这两种类型引入到 Swift 中:C 中 const 修饰的指针对应 UnsafePointer (最常见的应该就是 C 字符串的 const char * 了),而其他可变的指针则对应 UnsafeMutablePointer。除此之外,Swift 中存在表示一组连续数据指针的 UnsafeBufferPointer<T>,表示非完整结构的不透明指针 COpaquePointer 等等。另外你可能已经注意到了,能够确定指向内容的指针类型都是泛型的 struct,我们可以通过这个泛型来对指针指向的类型进行约束以提供一定安全性。

需要具体了解的看这篇:UnsafePointe<T>

顺便吐槽句哈,apple的代码也还有这种东西,也不知道是修改过的没有;


FIXME
  1. Equatable
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
=
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"
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"

而不相等的定义则完全是,自实现的相等操作取反:

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)
  }
}

这个实现是已经定义好的!!!

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
  }
}

从以上可以看出,==只是由实现好的静态函数决定,而===则是可以判断两个对象是否完全相等,这有点像判断两个指针相等一样,同样,我们要注意,如果两个可选对象都是nil,则也是===的;

  1. 搞清楚两个问题
上一篇下一篇

猜你喜欢

热点阅读