Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

掀起 Swift 的面紗

2,301 views

Published on

Talking about the implementation of basic types, sequence, collection and array in Swift Standard Library.

Published in: Engineering
  • Hi there! I just wanted to share a list of sites that helped me a lot during my studies: .................................................................................................................................... www.EssayWrite.best - Write an essay .................................................................................................................................... www.LitReview.xyz - Summary of books .................................................................................................................................... www.Coursework.best - Online coursework .................................................................................................................................... www.Dissertations.me - proquest dissertations .................................................................................................................................... www.ReMovie.club - Movies reviews .................................................................................................................................... www.WebSlides.vip - Best powerpoint presentations .................................................................................................................................... www.WritePaper.info - Write a research paper .................................................................................................................................... www.EddyHelp.com - Homework help online .................................................................................................................................... www.MyResumeHelp.net - Professional resume writing service .................................................................................................................................. www.HelpWriting.net - Help with writing any papers ......................................................................................................................................... Save so as not to lose
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

掀起 Swift 的面紗

  1. 1. 掀起 SWIFT 的⾯面紗 下班⾃我進修裝屌指南 Pofat @ iPlayground
  2. 2. 我是 Pofat
  3. 3. Clone 過 Android Source Code 嗎 讀過 Android Source Code 嗎? 對 Android Source Code 有什什麼感想? 起源
  4. 4. Swift Source Code 對⼯工作的幫助 0%
  5. 5. 如何開始 # Install cmake and ninja brew install cmake ninja mkdir swift-source cd swift-source # Clone Swift project to local git clone https://github.com/apple/swift.git ${ROOT} : swift-source here
  6. 6. 如何開始 - utils
  7. 7. # use update-checkout update all required repos ./swift/utils/update-checkout —clone
  8. 8. Compile 前準備
  9. 9. Compile! # Partially debug message ./swift/utils/build-script --release-debuginfo # Partially debug message ./swift/utils/build-script --debug # Partially debug message ./swift/utils/build-script --release
  10. 10. 檔案架構
  11. 11. 檔案架構 # build path (bin, gyb result, tests…) ${ROOT}/build/Ninja-RelWithDebInfoAssert/ swift-macosx-x86_64 # executables ${ROOT}/build/Ninja-RelWithDebInfoAssert/ swift-macosx-x86_64/bin ${BUILD_ROOT} : ${ROOT}/build/Ninja-RelWithDebInfoAssert/ swift-macosx-x86_64/
  12. 12. 檔案架構 # Original source file ${ROOT}/swift/stdlib/public/core # Converted swift files from gyb ${ROOT}/build/Ninja-RelWithDebInfoAssert/ swift-macosx-x86_64/stdlib/public/core/8
  13. 13. GYB? gyb --line-directive '' -o 
 /path/to/Some.swift Some.swift.gyb
  14. 14. @_fixed_layout public struct UInt8 : FixedWidthInteger, UnsignedInteger, _ExpressibleByBuiltinIntegerLiteral { /// A type that represents an integer literal. public typealias IntegerLiteralType = UInt8 @_transparent public init(_builtinIntegerLiteral x: _MaxBuiltinIntegerType) { _value = Builtin.s_to_u_checked_trunc_Int2048_Int8(x).0 } @_transparent public init(bitPattern x: Int8) { _value = x._value }
  15. 15. Tuple let a = (1, 2, 3, 4, 5, 6) let b = (1, 2, 3, 4, 5, 6) print("a == b ? (a == b)") a == b ? true
  16. 16. Tuple let c = (1, 2, 3, 4, 5, 6, 7) let d = (1, 2, 3, 4, 5, 6, 7) print("c == d ? (c == d)") error: binary operator '==' cannot be applied to two '(Int, Int, Int, Int, Int, Int, Int)' operands
  17. 17. Tuple’s GYB % for arity in range(2,7): % typeParams = [chr(ord("A") + i) for i in range(arity)] % tupleT = "({})".format(",".join(typeParams)) % equatableTypeParams = ", ".join(["{} : Equatable".format(c) for c in typeParams]) % originalTuple = "("a", {})".format(", ".join(map(str, range(1, arity)))) % greaterTuple = "("a", {})".format(", ".join(map(str, range(1, arity - 1) + [arity]))) // Tuple.swift.gyb
  18. 18. public func == <A : Comparable, B : Comparable, C : Comparable, D : Comparable, E : Comparable, F : Comparable>(lhs: (A,B,C,D,E,F), rhs: (A,B,C,D,E,F)) -> Bool {
 guard lhs.0 == rhs.0 { return false } return ( lhs.1, lhs.2, lhs.3, lhs.4, lhs.5 ) == ( rhs.1, rhs.2, rhs.3, rhs.4, rhs.5 )
 
 } // Tuple.swift
  19. 19. Optional @_frozen public enum Optional<Wrapped> : ExpressibleByNilLiteral { case none case some(Wrapped) @_transparent public init(_ some: Wrapped) { self = .some(some) } @_transparent public init(nilLiteral: ()) { self = .none } }
  20. 20. Optional - Map public func map<U>( _ transform: (Wrapped) throws -> U ) rethrows -> U? {
 switch self { case .some(let y): return .some(try transform(y)) case .none: return .none } }
  21. 21. Optional - flatMap public func flatMap<U>( _ transform: (Wrapped) throws -> U ) rethrows -> U? {
 switch self { case .some(let y): return try transform(y) case .none: return .none } }
  22. 22. Optional - Unwrap @_transparent public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T?) rethrows -> T? { switch optional { case .some(let value): return value case .none: return try defaultValue() } }
  23. 23. Bool @_fixed_layout public struct Bool { @usableFromInline internal var _value: Builtin.Int1 public init() { let zero: Int8 = 0 self._value = Builtin.trunc_Int8_Int1(zero._value) } }
  24. 24. ExpressibleByBooleanLiteral extension Bool: ExpressibleByBooleanLiteral { @_transparent public init(booleanLiteral value: Bool) { self = value } }
  25. 25. How to @autoclosure if measurement.count > 0 && sum / Double(measurement.count) < 5 { // do somehting.. } measurement.count might be ZERO!!
  26. 26. How to @autoclosure @_transparent @inline(__always) public static func && ( lhs: Bool, rhs: @autoclosure () throws -> Bool) rethrows -> Bool { return lhs ? try rhs() : false }
  27. 27. Attributes • @inlinable :expose not interface but source code, work when -O • @_transparent: must do inline even when -Onone • @_fixed_layout: Processed at SIL stage. It tells compiler that access properties by offset is possible without looking up metadata.
 

  28. 28. Attributes • @usableFromInline : Temporarily change scope only during inline stage. Include @inlinable
 
 
 
 
 
 
 
 @_fixed_layout public struct Bool { @usableFromInline internal var _value: Builtin.Int1 // …
  29. 29. What is Builtin ? Builtin.Int1
 Builtin.trunc_Int8_Int1(zero._value) 
 
 Builtin.s_to_u_checked_trunc_Int2048_Int8(x)
  30. 30. Integer Again public struct Int : FixedWidthInteger, SignedInteger, _ExpressibleByBuiltinIntegerLiteral { 
 public init(_builtinIntegerLiteral x: _MaxBuiltinIntegerType) { _value = Builtin.s_to_s_checked_trunc_Int2048_Int64(x).0 }
  31. 31. + public static func +(lhs: Int, rhs: Int) -> Int { var lhs = lhs lhs += rhs return lhs }
  32. 32. += public static func +=(lhs: inout Int, rhs: Int) { let (result, overflow) = Builtin.sadd_with_overflow_Int64( lhs._value, rhs._value, true._value) Builtin.condfail(overflow) lhs = Int(result) }
  33. 33. You may surprise… • Int is a struct in standard library • + is a global function declared in standard library • What an inefficient way !! Do we really implement basic arithmetic operations by cross-module function calls?
 

  34. 34. ObjC & Swift Compilation Clang Frontend ObjC LLVM LLVM IR Machine Code Swift Frontend Swift IRGen SIL Machine Code LLVM LLVM IR
  35. 35. Example // sum.swift let a = 1 let b = 2 let c = a + b $swiftc -emit-ir sum.swift
  36. 36. LLVM IR define i32 @main(i32, i8**) #0 { entry: %2 = bitcast i8** %1 to i8* store i64 1, i64* getelementptr inbounds (%TSi, %TSi* @"$S4test1aSivp", i32 0, i32 0), align 8 store i64 2, i64* getelementptr inbounds (%TSi, %TSi* @"$S4test1bSivp", i32 0, i32 0), align 8 %3 = load i64, i64* getelementptr inbounds (%TSi, %TSi* @"$S4test1aSivp", i32 0, i32 0), align 8 %4 = load i64, i64* getelementptr inbounds (%TSi, %TSi* @"$S4test1bSivp", i32 0, i32 0), align 8 %5 = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %3, i64 %4) %6 = extractvalue { i64, i1 } %5, 0 %7 = extractvalue { i64, i1 } %5, 1 br i1 %7, label %9, label %8
  37. 37. llvm::Intrinsic::ID swift::getLLVMIntrinsicIDForBuiltinWithOverflow(BuiltinValue Kind ID) { switch (ID) { default: break; case BuiltinValueKind::SAddOver: return llvm::Intrinsic::sadd_with_overflow; case BuiltinValueKind::UAddOver: return llvm::Intrinsic::uadd_with_overflow; case BuiltinValueKind::SSubOver: return llvm::Intrinsic::ssub_with_overflow; case BuiltinValueKind::USubOver: return llvm::Intrinsic::usub_with_overflow; case BuiltinValueKind::SMulOver: return llvm::Intrinsic::smul_with_overflow; case BuiltinValueKind::UMulOver: return llvm::Intrinsic::umul_with_overflow; } llvm_unreachable("Cannot convert the overflow builtin to llvm intrinsic."); } ${ROOT}/swift/lib/AST/Builtin.cpp
  38. 38. Builtin is a portal LLVM IR Builtin Builtin.type Builtin.method Standard Library TYPE METHOD SIL stage
  39. 39. How To Use Builtin. // builtin_add.swift import Swift let (result, overflow) = Builtin.sadd_with_overflow_Int64(1._value, 2._value, true._getBuiltinLogicValue()) print(Int(result)) $swiftc -parse-stdlib builtin_add.swift && ./builtin_add
  40. 40. @usableFromInline // builtin_add.swift import Swift let (result, overflow) = Builtin.sadd_with_overflow_Int64(1._value, 2._value, true._value) print(Int(result)) error: '_value' is inaccessible due to 'internal' protection level
  41. 41. Sequence https://swiftdoc.org/v4.2/protocol/sequence/hierarchy/
  42. 42. Sequence public protocol Sequence { associatedtype Element associatedtype Iterator : IteratorProtocol where Iterator.Element == Element func makeIterator() -> Iterator }
 public protocol IteratorProtocol { mutating func next() -> Element? }
  43. 43. Sequence public protocol Sequence { associatedtype Element associatedtype Iterator : IteratorProtocol where Iterator.Element == Element func makeIterator() -> Iterator }
 public protocol IteratorProtocol { mutating func next() -> Element? }
  44. 44. for (index, value) in mySeq.enumerated() { // do seomthing ... } O(1)
  45. 45. Enumerated /// - Complexity: O(1) @inlinabl public func enumerated() -> EnumeratedSequence<Self> { return EnumeratedSequence(_base: self) }
  46. 46. Enumerated public struct EnumeratedSequence<Base: Sequence> { internal var _base: Base internal init(_base: Base) { self._base = _base } }
  47. 47. for-in EnumeratedSequence extension EnumeratedSequence { public struct Iterator { internal var _base: Base.Iterator internal var _count: Int internal init(_base: Base.Iterator) { self._base = _base self._count = 0 } } }
  48. 48. for-in EnumeratedSequence extension EnumeratedSequence.Iterator: IteratorProtocol, Sequence { public typealias Element = (offset: Int, element: Base.Element) public mutating func next() -> Element? { guard let b = _base.next() else { return nil } let result = (offset: _count, element: b) _count += 1 return result } }
  49. 49. Map public func map<T>( _ transform: (Element) throws -> T ) rethrows -> [T] {
 let initialCapacity = underestimatedCount var result = ContiguousArray<T>() result.reserveCapacity(initialCapacity) var iterator = self.makeIterator() // lower half of map func
  50. 50. Map // upper half of map func for _ in 0..<initialCapacity { result.append(try transform(iterator.next()!)) } while let element = iterator.next() { result.append(try transform(element)) } return Array(result) }
  51. 51. Reduce public func reduce<Result>( _ initialResult: Result, _ nextPartialResult: (_ partialResult: Result, Element) throws -> Result ) rethrows -> Result {
 var accumulator = initialResult for element in self { accumulator = try nextPartialResult(accumulator, element) }
 return accumulator }
  52. 52. Reduce Into public func reduce<Result>( into initialResult: Result, _ updateAccumulatingResult: (_ partialResult: inout Result, Element) throws -> () ) rethrows -> Result { var accumulator = initialResult for element in self { try updateAccumulatingResult(&accumulator, element) } return accumulator } }
  53. 53. flatMap public func flatMap<SegmentOfResult : Sequence>( _ transform: (Element) throws -> SegmentOfResult ) rethrows -> [SegmentOfResult.Element] {
 var result: [SegmentOfResult.Element] = [] for element in self { result.append(contentsOf: try transform(element)) }
 return result }
  54. 54. compactMap public func compactMap<ElementOfResult>( _ transform: (Element) throws -> ElementOfResult? ) rethrows -> [ElementOfResult] {
 return try _compactMap(transform)
 }
  55. 55. public func _compactMap<ElementOfResult>( _ transform: (Element) throws -> ElementOfResult? ) rethrows -> [ElementOfResult] {
 var result: [ElementOfResult] = []
 for element in self { if let newElement = try transform(element) { result.append(newElement) } }
 return result }
  56. 56. They are EAGER
  57. 57. class FileReadIterator: IteratorProtocol { 
 private let handler = FileHandle(forReadingAtPath: "/path/to/large_file")! func next() -> UInt8? { let data = handler.readData(ofLength: 1) return data[0] } 
 deinit { handler.closeFile() } }
  58. 58. let fileSequence = AnySequence { FileReadIterator() }
 let batchOperation = fileSequence.map{ print($0) }
  59. 59. Make It LAZY
  60. 60. Lazy Sequence extension Sequence {
 public var lazy: LazySequence<Self> { return LazySequence(_base: self) }
 }
  61. 61. LazySequence public struct LazySequence<Base : Sequence>: _SequenceWrapper {
 public var _base: Base internal init(_base: Base) { self._base = _base } }
  62. 62. LazySequenceProtocol extension LazySequenceProtocol { public func map<U>( _ transform: @escaping (Elements.Element) -> U ) -> LazyMapSequence<Self.Elements, U> { return LazyMapSequence(_base: self.elements, transform: transform) } }
  63. 63. public struct LazyMapSequence<Base : Sequence, Element> { internal var _base: Base internal let _transform: (Base.Element) -> Element internal init(_base: Base, transform: @escaping (Base.Element) -> Element) {
 self._base = _base self._transform = transform
 } }
  64. 64. extension LazyMapSequence.Iterator: IteratorProtocol, Sequence { public mutating func next() -> Element? {
 return _base.next().map(_transform)
 } }
  65. 65. File Reader Revised let fileSequence = AnySequence { FileReadIterator() }
 let lazyBatch = fileSequence.lazy.map{ print($0)} var batchIterator = lazyBatch.makeIterator() for _ in 1 ... 10 { batchIterator.next() }
  66. 66. File Reader Revised let fileSequence = AnySequence { FileReadIterator() }
 let lazyBatch = fileSequence.lazy.map{ print($0)} var batchIterator = lazyBatch.makeIterator() for _ in 1 ... 1024 { batchIterator.next() }
  67. 67. Collection https://swiftdoc.org/v4.2/protocol/collection/hierarchy/
  68. 68. Collection remove(at:) problem for obj in objsToDelete { myCollection.remove(at: myCollection.index(of: obj)!) } O(N)
  69. 69. Collection removeAll(where:) extension RangeReplaceableCollection {
 public mutating func removeAll( where shouldBeRemoved: (Element) throws -> Bool ) rethrows {
 let suffixStart = try _halfStablePartition(isSuffixElement: shouldBeRemoved)
 removeSubrange(suffixStart…) } }
  70. 70. mutating func _halfStablePartition( isSuffixElement: (Element) throws -> Bool ) rethrows -> Index {
 guard var i = try firstIndex(where: isSuffixElement) else { return endIndex } var j = index(after: i) while j != endIndex { if try !isSuffixElement(self[j]) { swapAt(i, j); formIndex(after: &i) } formIndex(after: &j) }
 return i }
  71. 71. mutating func _halfStablePartition( isSuffixElement: (Element) throws -> Bool ) rethrows -> Index {
 guard var i = try firstIndex(where: isSuffixElement) else { return endIndex } var j = index(after: i)
 while j != endIndex { if try !isSuffixElement(self[j]) { swapAt(i, j) formIndex(after: &i) } formIndex(after: &j) }
 return i } OH! It’s moving zeros!
  72. 72. Array
  73. 73. Inside Array public struct Array<Element>: _DestructorSafeContainer { #if _runtime(_ObjC) internal typealias _Buffer = _ArrayBuffer<Element> #endif internal var _buffer: _Buffer internal init(_buffer: _Buffer) { self._buffer = _buffer } }
  74. 74. struct Array _buffer struct _ArrayBuffer _storage struct _BridgStorage _rawValue Contiguous Array
 or NSArray Builtin.BridgeObject
  75. 75. Copy On Write mutating func append(_ newElement: __owned Element) { _makeUniqueAndReserveCapacityIfNotUnique()
 let oldCount = _getCount() _reserveCapacityAssumingUniqueBuffer(oldCount: oldCount)
 _appendElementAssumeUniqueAndCapacity(oldCount, newElement: newElement) }
  76. 76. Copy If Not Unique mutating func _makeUniqueAndReserveCapacityIfNotUnique() { if _slowPath(! _buffer.isMutableAndUniquelyReferenced()) { _copyToNewBuffer(oldCount: _buffer.count) } }
  77. 77. isUnique mutating func isMutableAndUniquelyReferenced() -> Bool { return isUniquelyReferenced() }

  78. 78. isUnique mutating func isUniquelyReferenced() -> Bool {
 if !_isClassOrObjCExistential(Element.self) { return _storage.isUniquelyReferenced_native_noSpareBits() } if !_storage.isUniquelyReferencedNative() { return false }
 return _isNative }

  79. 79. Copy To New Buffer mutating func _copyToNewBuffer(oldCount: Int) { let newCount = oldCount + 1 var newBuffer = _buffer._forceCreateUniqueMutableBuffer( countForNewBuffer: oldCount, minNewCapacity: newCount) _buffer._arrayOutOfPlaceUpdate(&newBuffer, oldCount, 0) }
  80. 80. What If Reach Full Capacity func _forceCreateUniqueMutableBufferImpl( countForBuffer: Int, minNewCapacity: Int, requiredCapacity: Int ) -> _ContiguousArrayBuffer<Element> { let minimumCapacity = Swift.max(requiredCapacity, minNewCapacity > capacity ? _growArrayCapacity(capacity) : capacity) return _ContiguousArrayBuffer( _uninitializedCount: countForBuffer, minimumCapacity: minimumCapacity) }
  81. 81. Array Grow func _growArrayCapacity(_ capacity: Int) -> Int { return capacity * 2 }
  82. 82. Array Is Not Thread Safe import Dispatch var array = [Int]() DispatchQueue.concurrentPerform(iterations: 50) { index in let last = array.last ?? 0 array.append(last + 1) } print("array count: (array.count)")
  83. 83. var array = [1, 2, 3, 4, 5] let arrayAccessQueue = DispatchQueue(label: "array", qos: .utility, attributes: .concurrent) // read var readValue: Int = 0 arrayAccessQueue.sync { readValue = array[0] } // write arrayAccessQueue.async(flags: .barrier) { array.append(6) } // thread_safe_access_array.swift
  84. 84. Sorting Array mutating func sort( by areInIncreasingOrder: (Element, Element) throws -> Bool ) rethrows { let didSortUnsafeBuffer = try _withUnsafeMutableBufferPointerIfSupported { buffer -> Void? in try buffer.sort(by: areInIncreasingOrder) } if didSortUnsafeBuffer == nil { try _introSort(within: startIndex..<endIndex, by: areInIncreasingOrder) } }
  85. 85. Insertion / Intro / Heap mutating func _introSortImpl( within range: Range<Index>, by areInIncreasingOrder: (Element, Element) throws -> Bool, depthLimit: Int ) rethrows { if distance(from: range.lowerBound, to: range.upperBound) < 20 { try _insertionSort(within: range, by: areInIncreasingOrder) } else if depthLimit == 0 { try _heapSort(within: range, by: areInIncreasingOrder) } else { let partIdx = try _partition(within: range, by: areInIncreasingOrder) try _introSortImpl( within: range.lowerBound..<partIdx, by: areInIncreasingOrder, depthLimit: depthLimit &- 1) try _introSortImpl( within: partIdx..<range.upperBound, by: areInIncreasingOrder, depthLimit: depthLimit &- 1) } }
  86. 86. Sorting Strategy mutating func _introSortImpl( within range: Range<Index>, by areInIncreasingOrder: (Element, Element) throws -> Bool, depthLimit: Int ) rethrows { if distance(from: range.lowerBound, to: range.upperBound) < 20 { try _insertionSort(within: range, by: areInIncreasingOrder) } else if depthLimit == 0 { try _heapSort(within: range, by: areInIncreasingOrder) } else { let partIdx = try _partition(within: range, by: areInIncreasingOrder) try _introSortImpl( within: range.lowerBound..<partIdx, by: areInIncreasingOrder, depthLimit: depthLimit &- 1) try _introSortImpl( within: partIdx..<range.upperBound, by: areInIncreasingOrder, depthLimit: depthLimit &- 1) } }
  87. 87. Sorting Strategy mutating func _introSortImpl( within range: Range<Index>, by areInIncreasingOrder: (Element, Element) throws -> Bool, depthLimit: Int ) rethrows { if distance(from: range.lowerBound, to: range.upperBound) < 20 { try _insertionSort(within: range, by: areInIncreasingOrder) } else if depthLimit == 0 { try _heapSort(within: range, by: areInIncreasingOrder) } else { let partIdx = try _partition(within: range, by: areInIncreasingOrder) try _introSortImpl( within: range.lowerBound..<partIdx, by: areInIncreasingOrder, depthLimit: depthLimit &- 1) try _introSortImpl( within: partIdx..<range.upperBound, by: areInIncreasingOrder, depthLimit: depthLimit &- 1) } }
  88. 88. Develop Swift !! Better Reduce: User first element in sequence as initial value
  89. 89. Test FIRST!
  90. 90. SequenceTypeTests.test("betterReduce") { let animals = ["Antelope", "Butterfly", "Camel", “Dolphin"] var timesClosureWasCalled = 0 let longestAnimal = animals.betterReduce { current, animal in timesClousreWasCalled += 1 if current.count > animal.count { return current } else { return animal } } ?? “" // expects … } // ${ROOT}/swift/validation-test/stdlib/SequenceType.swift.gyb
  91. 91. SequenceTypeTests.test("betterReduce") { // Codes … expectEqual(longestAnimal, “Butterfly") expectEqual( animals.count, timesClosureWasCalled, "betterReduce() should be eager”) } // ${ROOT}/swift/validation-test/stdlib/SequenceType.swift.gyb
  92. 92. Now CODE!!
  93. 93. // SequenceAlgorithm.swift — extension Sequence @inlinable public func betterReduce( _ nextPartialResult: (_ partialResult: Element, Element) throws -> Element ) rethrows -> Element? {
 var i = makeIterator() guard var accumulated = i.next() else { return nil } while let element = i.next() { accumulated = try nextPartialResult(accumulated, element) } return accumulated }
  94. 94. Test Swift!! ./swift/utils/build-script -r -tCompile and test ./swift/utils/build-script -r -T Compile and validation test 4XXX tests!! 10000+ tests!!
  95. 95. Test Standard Library Only ./llvm/utils/lit/lit.py -sv ${BUILD_ROOT}/swift- macosx-x86_64/test-macosx-x86_64/stdlib A full-test run is suggested in the first place ./llvm/utils/lit/lit.py -sv ${BUILD_ROOT}/ swift-macosx-x86_64/validation-test-macosx- x86_64/stdlib
  96. 96. sh ${BUILD_ROOT}/validation-test-macosx-x86_64/stdlib/Output/ Bool.swift.script Now you can do single test with
  97. 97. Wait! Not compiled yet…
  98. 98. ${BUILD_ROOT} ninja swift-stdlib Thanks to ninja, lets build standard library only sh ${BUILD_RTTO}/validation-test-macosx-x86_64/
 stdlib/Output/SequenceType.swift.gyb.script And do test!!
  99. 99. 😎
  100. 100. 所以,看 Source Code到底有何幫助??
  101. 101. 參參考來來源 • https://github.com/apple/swift • 喵神 Swift 标准库源码导读 
  102. 102. 我的裝屌指南系列列 • EP I: GitHub 裝屌指南 • EP II: Vim 裝屌指南 • EP III: Debug 裝屌指南
  103. 103. 講完惹 關愛 Swift 發展者或想討論 ,歡迎和我聯聯繫 tjazzterATgmailDOTcom

×