跳转到内容
Skip 中文站
3.2k

SkipLib

为 Skip Lite 转译后的 Swift 提供 Swift 标准库支持。

在此处查看当前已实现的 API。

SkipLib 提供 skip.lib Kotlin 包,主要有两个用途:

  1. SkipLib 是面向 Android Kotlin 的 Swift 标准库重新实现。它的目标是尽可能完整地映射 Swift 标准库,让 Skip 开发者能够放心使用 Swift 标准库 API。
  2. SkipLib 还包含 Skip 转译器在将 Swift 源代码转换为等价 Kotlin 代码时使用的自定义 Kotlin API。例如,Kotlin 语言本身没有元组,因此 SkipLib 的 Tuple.kt 定义了专用的 Kotlin Tuple 类。转译器处理引用元组的 Swift 代码时,会在生成的 Kotlin 代码中使用这些 Tuple 类。

SkipLib 依赖 skip ↗ 转译器插件,没有其他库依赖。

它属于核心的 Skip Core Frameworks,并不建议直接导入。 Skip 转译器会自动向转译后的文件添加 import skip.lib.*,因此该模块会被透明地引入。

  • SkipLib 的 Swift 符号文件(参见实现策略)名义上已经完整,应当声明了全部 Swift 标准库 API。不过这一点很难全面验证;如果发现遗漏,请向我们报告问题 ↗。
  • 尚未实现的 API 会使用 @available(*, unavailable) 注解标记。尝试使用这类 API 时,Skip 会生成错误。
  • 尤其是集合 API,目前仍有相当一部分尚未实现。
  • 单元测试尚未做到全面覆盖。

参见 Swift 标准库支持。

欢迎为 SkipLib 贡献代码。Skip 产品的文档包含本地开发 Skip 库时很有帮助的说明与技巧。

当前最迫切的任务是减少尚未实现的 API。若要帮助补齐 SkipLib 中未实现的 API:

  1. 找到尚未实现的 API。未实现的 API 应当在 Swift 符号文件中标记为 @available(*, unavailable)。
  2. 编写合适的 Kotlin 实现。参见下方的实现策略。对于集合 API,请确保也为 String 提供对应实现。
  3. 编写单元测试。
  4. 提交 PR。 ↗

也欢迎测试用例、注释和文档等其他形式的贡献!

除 Skip 转译器本身外,SkipLib 实现的是 Swift 语言最底层的能力,因此它的实现策略与其他 Skip 库有所不同。

大多数 Skip 库以 Swift 编写、调用 Kotlin API,并依靠 Skip 转译器转换为 Kotlin;但 SkipLib 的大部分代码由纯 Kotlin 编写。以 SkipLib 对 Swift Array 的实现为例,其 Array 支持分为两个文件:

  1. Sources/SkipLib/Array.swift 相当于 Swift 头文件:它声明 Array 类型的 Swift API,但只提供空实现。文件顶部的 // SKIP SYMBOLFILE 注释用于标记此用途。关于 Skip 特殊注释的更多说明,请参阅 Skip 产品文档。
  2. Sources/SkipLib/Skip/Array.kt 包含以 Kotlin 编写的实际 Array 实现。

SkipLib 中的大多数 Swift 类型都采用这种模式。与此同时,对于直接内建于 Swift 语言中的结构(例如元组或 inout 参数),SkipLib 的实现只有 Kotlin 文件,并不存在对应的 Swift 符号文件。

下表汇总了 SkipLib 在 Android 上对 Swift 标准库 API 的支持情况。未列出的内容很可能尚不受支持。请注意,在仅用于 iOS 的代码中(即 #if !SKIP 代码块内),你可以使用任意 API。

支持级别:

  • ✅ – 完整支持
  • 🟢 – 高度支持
  • 🟡 - 中等支持
  • 🟠 – 少量支持
支持度API
🟢
Actor
  • 不支持非私有可变属性
✅ Any
✅ AnyActor
✅ AnyHashable
✅ AnyObject
🟢
Array
  • init()
  • init(repeating: Element, count: Int)
  • init(_ sequence: any Sequence<Element>)
  • 集合 API 的支持情况请参见 Collection
✅ assert
✅ assertionFailure
✅ AsyncSequence
✅
AsyncStream
  • 调用 init(unfolding:) 构造器时,请使用带标签的参数,不要使用尾随闭包
🟢
Bool
  • static func random() -> Bool
  • static func random(using gen: inout RandomNumberGenerator) -> Bool
✅ CaseIterable
✅ CGAffineTransform
✅ CGFloat
✅ CGPoint
✅ CGRect
✅ CGSize
🟢
Character
  • init(_: Character)
  • init(_: String)
  • var isNewline: Bool
  • var isWhitespace: Bool
  • var isUppercase: Bool
  • var isLowercase: Bool
  • func lowercased() -> String
  • func uppercased() -> String
🟢
Codable
🟡
Collection
  • 注意:此列表汇总了 Swift 多种集合类型所支持的 API,包括 Sequence、Collection、BidirectionalCollection 等
  • func allSatisfy(_ predicate: (Element) throws -> Bool) rethrows -> Bool
  • mutating func append(_ newElement: Element)
  • mutating func append(contentsOf newElements: any Sequence<Element>)
  • func contains(_ element: Element) -> Bool
  • func contains(where predicate: (Element) throws -> Bool) rethrows -> Bool
  • func distance(from start: Int, to end: Int) -> Int
  • func drop(while predicate: (Element) throws -> Bool) rethrows -> [Element]
  • func dropFirst(_ k: Int = 1) -> [Element]
  • func dropLast(_ k: Int = 1) -> [Element]
  • func elementsEqual(_ other: any Sequence<Element>) -> Bool
  • func elementsEqual(_ other: any Sequence<Element>, by areEquivalent: (Element, Element) throws -> Bool) rethrows -> Bool
  • func enumerated() -> any Sequence<(offset: Int, element: Element)>
  • var endIndex: Int
  • func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> [Element]
  • func first(where predicate: (Element) throws -> Bool) rethrows -> Element?
  • func firstIndex(of element: Element) -> Int?
  • func firstIndex(where predicate: (Element) throws -> Bool) rethrows -> Int?
  • var first: Element?
  • func flatMap<RE>(_ transform: (Element) throws -> any Sequence<RE>) rethrows -> [RE]
  • func formIndex(_ i: inout Int, offsetBy distance: Int)
  • func formIndex(after i: inout Int)
  • func index(_ i: Int, offsetBy distance: Int) -> Int
  • func index(after i: Int) -> Int
  • var indices: any Sequence<Int>
  • var isEmpty: Bool
  • func joined<RE>() -> [RE] where Element: Sequence<RE>
  • func joined<RE>(separator: any Sequence<RE>) -> [RE] where Element: Sequence<RE>
  • func joined(separator: String) -> String
  • func makeIterator() -> any IteratorProtocol<Element>
  • func map<RE>(_ transform: (Element) throws -> RE) rethrows -> [RE]
  • func max() -> Element?
  • func max(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element?
  • func min() -> Element?
  • func min(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element?
  • var underestimatedCount: Int
  • func prefix(_ maxLength: Int) -> [Element]
  • func prefix(through end: Int) -> [Element]
  • func prefix(upTo end: Int) -> [Element]
  • mutating func popFirst() -> Element?
  • mutating func popLast() -> Element?
  • func randomElement() -> Element?
  • func randomElement(using generator: inout any RandomNumberGenerator) -> Element?
  • func reduce<R>(_ initialResult: R, _ nextPartialResult: (_ partialResult: R, Element) throws -> R) rethrows -> R
  • func reduce<R>(into initialResult: R, _ updateAccumulatingResult: (_ partialResult: inout R, Element) throws -> Void) rethrows -> R
  • func remove(at i: Int) -> Element
  • mutating func removeAll(keepingCapacity keepCapacity: Bool = false)
  • mutating func removeAll(where shouldBeRemoved: (Element) throws -> Bool) rethrows
  • mutating func removeFirst() -> Element
  • mutating func removeFirst(_ k: Int)
  • mutating func removeLast() -> Element
  • mutating func removeLast(_ k: Int)
  • mutating func reverse()
  • func reversed() -> [Element]
  • mutating func shuffle()
  • mutating func shuffle<T: RandomNumberGenerator>(using generator: inout T)
  • mutating func sort()
  • mutating func sort(by areIncreasingOrder: (Element, Element) throws -> Bool) rethrows
  • mutating func swapAt(_ i: Int, _ j: Int)
  • subscript(bounds: Range<Int>) -> any Collection<Element>
  • subscript(position: Int) -> Element
  • func starts(with possiblePrefix: Any) -> Bool
  • func starts(with possiblePrefix: Any, by areEquivalent: (Element, Element) throws -> Bool) rethrows -> Bool
  • func suffix(from start: Int) -> [Element]
  • func suffix(_ maxLength: Int) -> [Element]
  • func sorted() -> [Element]
  • func sorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element]
  • var startIndex: Int
  • var count: Int
  • func count<E>(where: (E) throws -> Bool) rethrows -> Int
  • func withContiguousStorageIfAvailable<R>(_ body: (Any) throws -> R) rethrows -> R?
  • func forEach(_ body: (Element) throws -> Void) rethrows
  • func drop(while predicate: (Element) throws -> Bool) rethrows -> [Element]
  • func dropFirst(_ k: Int = 1) -> [Element]
  • func dropLast(_ k: Int = 1) -> [Element]
  • func enumerated() -> any Sequence<(offset: Int, element: Element)>
  • func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> [Element]
  • func first(where predicate: (Element) throws -> Bool) rethrows -> Element?
  • func map<RE>(_ transform: (Element) throws -> RE) rethrows -> [RE]
  • func max(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element?
  • func min(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element?
  • func reduce<R>(_ initialResult: R, _ nextPartialResult: (_ partialResult: R, Element) throws -> R) rethrows -> R
  • func reduce<R>(into initialResult: R, _ updateAccumulatingResult: (_ partialResult: inout R, Element) throws -> Void) rethrows -> R
  • func reversed() -> [Element]
  • func shuffled() -> [Element]
  • func shuffled<T: RandomNumberGenerator>(using generator: inout T) -> [Element]
  • func flatMap<RE>(_ transform: (Element) throws -> any Sequence<RE>) rethrows -> [RE]
  • func compactMap<RE>(_ transform: (Element) throws -> RE?) rethrows -> [RE]
  • func sorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element]
  • func joined<RE>() -> [RE] where Element: Sequence<RE>
  • func joined<RE>(separator: any Sequence<RE>) -> [RE] where Element: Sequence<RE>
  • func joined(separator: String) -> String
  • func starts(with possiblePrefix: Any) -> Bool
  • func contains(_ element: Element) -> Bool
  • func min() -> Element?
  • func max() -> Element?
  • func sorted() -> [Element]
  • var startIndex: Int
  • var endIndex: Int
  • var indices: any Sequence<Int>
  • func index(_ i: Int, offsetBy distance: Int) -> Int
  • func distance(from start: Int, to end: Int) -> Int
  • func index(after i: Int) -> Int
  • func formIndex(after i: inout Int)
  • func formIndex(_ i: inout Int, offsetBy distance: Int)
  • func randomElement() -> Element?
  • func randomElement(using generator: inout any RandomNumberGenerator) -> Element?
  • mutating func popFirst() -> Element?
  • var first: Element?
  • func prefix(upTo end: Int) -> [Element]
  • func suffix(from start: Int) -> [Element]
  • func prefix(through end: Int) -> [Element]
  • mutating func removeFirst() -> Element
  • mutating func removeFirst(_ k: Int)
  • func firstIndex(of element: Element) -> Int?
  • func firstIndex(where predicate: (Element) throws -> Bool) rethrows -> Int?
  • mutating func shuffle()
  • mutating func shuffle<T: RandomNumberGenerator>(using generator: inout T)
  • mutating func sort()
  • mutating func sort(by areIncreasingOrder: (Element, Element) throws -> Bool) rethrows
  • mutating func reverse()
  • mutating func swapAt(_ i: Int, _ j: Int)
  • mutating func append(_ newElement: Element)
  • mutating func append(contentsOf newElements: any Sequence<Element>)
  • mutating func insert(_ newElement: Element, at i: Int)
  • mutating func insert(contentsOf newElements: any Sequence<Element>, at i: Int)
  • mutating func remove(at i: Int) -> Element
  • mutating func removeAll(keepingCapacity keepCapacity: Bool = false)
  • mutating func removeAll(where shouldBeRemoved: (Element) throws -> Bool) rethrows
  • mutating func popLast() -> Element?
  • mutating func removeLast() -> Element
  • mutating func removeLast(_ k: Int)
  • subscript(bounds: Range<Int>) -> any Collection<Element>
  • subscript(position: Int) -> Element
✅ Comparable
✅ CustomDebugStringConvertible
✅ CustomStringConvertible
🟢
Decodable
🟢
Dictionary
  • init()
  • init(minimumCapacity: Int)
  • init(uniqueKeysWithValues keysAndValues: any Sequence<(Key, Value)>)
  • func filter(_ isIncluded: ((Key, Value)) throws -> Bool) rethrows -> Dictionary<Key, Value>
  • subscript(key: Key) -> Value?
  • subscript(key: Key, default defaultValue: Value) -> Value
  • func mapValues<T>(_ transform: (Value) throws -> T) rethrows -> Dictionary<Key, T>
  • func compactMapValues<T>(_ transform: (Value) throws -> T?) rethrows -> Dictionary<Key, T>
  • mutating func updateValue(_ value: Value, forKey key: Key) -> Value?
  • mutating func removeValue(forKey key: Key) -> Value?
  • var keys: any Collection<Key>)
  • var values: any Collection<Value>
  • mutating func removeAll(keepingCapacity keepCapacity: Bool = false)
  • 集合 API 的支持情况请参见 Collection
✅ DiscardingTaskGroup
🟢
Double
  • static var nan: Double
  • static var infinity: Double
  • static var pi: Double
  • var isNan: Bool
  • var isFinite: Bool
  • var isInfinite: Bool
  • static func random(in range: Range<Double>) -> Double
  • func rounded() -> Double
  • func rounded(_ rule: FloatingPointRoundingRule) -> Double
🟢
Encodable
  • 参见 [Codable](#codable)
✅ Equatable
✅ Error
✅ fatalError
🟢
Float
  • static var nan: Float
  • static var infinity: Float
  • static var pi: Float
  • var isNan: Bool
  • var isFinite: Bool
  • var isInfinite: Bool
  • static func random(in range: Range<Float>) -> Float
  • func rounded() -> Float
  • func rounded(_ rule: FloatingPointRoundingRule) -> Float
✅ Hashable
✅ Hasher
✅ Identifiable
🟢
Int8
  • static var min: Int8
  • static var max: Int8
  • static func random(in range: Range<Int8>) -> Int8
  • static func random(in range: Range<Int8>, using gen: inout RandomNumberGenerator) -> Int8
🟢
Int16
  • static var min: Int16
  • static var max: Int16
  • static func random(in range: Range<Int16>) -> Int16
  • static func random(in range: Range<Int16>, using gen: inout RandomNumberGenerator) -> Int16
🟢
Int32
  • static var min: Int32
  • static var max: Int32
  • static func random(in range: Range<Int32>) -> Int32
  • static func random(in range: Range<Int32>, using gen: inout RandomNumberGenerator) -> Int32
🟢
Int
  • Kotlin 的 Int 为 32 位
  • static var min: Int
  • static var max: Int
  • static func random(in range: Range<Int>) -> Int
  • static func random(in range: Range<Int>, using gen: inout RandomNumberGenerator) -> Int
🟢
Int64
  • static var min: Int64
  • static var max: Int64
  • static func random(in range: Range<Int64>) -> Int64
  • static func random(in range: Range<Int64>, using gen: inout RandomNumberGenerator) -> Int64
🟢 @MainActor
🟢
MainActor
  • static func run<T>(body: () throws -> T) async -> T
🟢
math.h
  • var M_E: Double
  • var M_LOG2E: Double
  • var M_LOG10E: Double
  • var M_LN2: Double
  • var M_LN10: Double
  • var M_PI: Double
  • func acosf(_ x: Float) -> Float
  • func acos(_ x: Double) -> Double
  • func acosl(_ x: Double) -> Double
  • func asinf(_ x: Float) -> Float
  • func asin(_ x: Double) -> Double
  • func asinl(_ x: Double) -> Double
  • func atanf(_ x: Float) -> Float
  • func atan(_ x: Double) -> Double
  • func atanl(_ x: Double) -> Double
  • func atan2f(_ x: Float, _ y: Float) -> Float
  • func atan2(_ x: Double, _ y: Double) -> Double
  • func atan2l(_ x: Double, _ y: Double) -> Double
  • func cosf(_ x: Float) -> Float
  • func cos(_ x: Double) -> Double
  • func cosl(_ x: Double) -> Double
  • func sinf(_ x: Float) -> Float
  • func sin(_ x: Double) -> Double
  • func sinl(_ x: Double) -> Double
  • func tanf(_ x: Float) -> Float
  • func tan(_ x: Double) -> Double
  • func tanl(_ x: Double) -> Double
  • func acoshf(_ x: Float) -> Float
  • func acosh(_ x: Double) -> Double
  • func acoshl(_ x: Double) -> Double
  • func asinhf(_ x: Float) -> Float
  • func asinh(_ x: Double) -> Double
  • func asinhl(_ x: Double) -> Double
  • func atanhf(_ x: Float) -> Float
  • func atanh(_ x: Double) -> Double
  • func atanhl(_ x: Double) -> Double
  • func coshf(_ x: Float) -> Float
  • func cosh(_ x: Double) -> Double
  • func coshl(_ x: Double) -> Double
  • func sinhf(_ x: Float) -> Float
  • func sinh(_ x: Double) -> Double
  • func sinhl(_ x: Double) -> Double
  • func tanhf(_ x: Float) -> Float
  • func tanh(_ x: Double) -> Double
  • func tanhl(_ x: Double) -> Double
  • func expf(_ x: Float) -> Float
  • func exp(_ x: Double) -> Double
  • func expl(_ x: Double) -> Double
  • func exp2f(_ x: Float) -> Float
  • func exp2(_ x: Double) -> Double
  • func exp2l(_ x: Double) -> Double
  • func expm1f(_ x: Float) -> Float
  • func expm1(_ x: Double) -> Double
  • func expm1l(_ x: Double) -> Double
  • func logf(_ x: Float) -> Float
  • func log(_ x: Double) -> Double
  • func logl(_ x: Double) -> Double
  • func log10f(_ x: Float) -> Float
  • func log10(_ x: Double) -> Double
  • func log10l(_ x: Double) -> Double
  • func log2f(_ x: Float) -> Float
  • func log2(_ x: Double) -> Double
  • func log2l(_ x: Double) -> Double
  • func log1pf(_ x: Float) -> Float
  • func log1p(_ x: Double) -> Double
  • func log1pl(_ x: Double) -> Double
  • func logbf(_ x: Float) -> Float
  • func logb(_ x: Double) -> Double
  • func logbl(_ x: Double) -> Double
  • func abs(_ x: Double) -> Double
  • func abs(_ x: Int) -> Int
  • func abs(_ x: Int64) -> Int64
  • func fabsf(_ x: Float) -> Float
  • func fabs(_ x: Double) -> Double
  • func fabsl(_ x: Double) -> Double
  • func cbrtf(_ x: Float) -> Float
  • func cbrt(_ x: Double) -> Double
  • func cbrtl(_ x: Double) -> Double
  • func hypotf(_ x: Float, _ y: Float) -> Float
  • func hypot(_ x: Double, _ y: Double) -> Double
  • func hypotl(_ x: Double, _ y: Double) -> Double
  • func powf(_ x: Float, _ y: Float) -> Float
  • func pow(_ x: Double, _ y: Double) -> Double
  • func powl(_ x: Double, _ y: Double) -> Double
  • func sqrtf(_ x: Float) -> Float
  • func sqrt(_ x: Double) -> Double
  • func sqrtl(_ x: Double) -> Double
  • func ceilf(_ x: Float) -> Float
  • func ceil(_ x: Double) -> Double
  • func ceill(_ x: Double) -> Double
  • func floorf(_ x: Float) -> Float
  • func floor(_ x: Double) -> Double
  • func floorl(_ x: Double) -> Double
  • func roundf(_ x: Float) -> Float
  • func round(_ x: Double) -> Double
  • func roundl(_ x: Double) -> Double
  • func fmodf(_ x: Float, _ y: Float) -> Float
  • func fmod(_ x: Double, _ y: Double) -> Double
  • func fmodl(_ x: Double, _ y: Double) -> Double
  • func remainderf(_ x: Float, _ y: Float) -> Float
  • func remainder(_ x: Double, _ y: Double) -> Double
  • func remainderl(_ x: Double, _ y: Double) -> Double
  • func fmaxf(_ x: Float, _ y: Float) -> Float
  • func fmax(_ x: Double, _ y: Double) -> Double
  • func fmaxl(_ x: Double, _ y: Double) -> Double
  • func fminf(_ x: Float, _ y: Float) -> Float
  • func fmin(_ x: Double, _ y: Double) -> Double
  • func fminl(_ x: Double, _ y: Double) -> Double
✅ max(_:_:)
✅ min(_:_:)
✅ ObjectIdentifier
✅ OptionSet
✅ precondition
✅ preconditionFailure
✅ RandomNumberGenerator
🟠
Range
  • 通常只支持 Range<Int>
  • var lowerBound: Bound
  • var upperBound: Bound
  • func contains(_ element: Bound) -> Bool
  • var isEmpty: Bool
  • func map<RE>(_ transform: (Bound) throws -> RE) rethrows -> [RE]
✅ RawRepresentable
🟠
Regex
  • init(_ string: String)
  • func matches(_ string: String) -> [Match]
  • func replace(_ string: String, with replacement: String) -> String
🟠
Regex.Match
  • var count: Int
  • subscript(index: Int) -> MatchGroup
🟠
Regex.MatchGroup
  • var substring: Substring?
✅ Result
🟡
swap(_:_:)
  • 不支持交换数组及其他数据结构中的值
🟢
Set
  • init()
  • init(_ sequence: any Sequence<Element>)
  • 参见 Collection
  • 参见 SetAlgebra
🟢
SetAlgebra
  • func contains(_ element: Element) -> Bool
  • func union(_ other: Self) -> Self
  • func intersection(_ other: Self) -> Self
  • func symmetricDifference(_ other: Self) -> Self
  • mutating func insert(_ newMember: Element) -> (inserted: Bool, memberAfterInsert: Element)
  • mutating func remove(_ member: Element) -> Element?
  • mutating func update(with newMember: Element) -> Element?
  • mutating func formUnion(_ other: Self)
  • mutating func formIntersection(_ other: Self)
  • mutating func formSymmetricDifference(_ other: Self)
  • func subtracting(_ other: Self) -> Self
  • func isSubset(of other: Self) -> Bool
  • func isDisjoint(with other: Self) -> Bool
  • func isSuperset(of other: Self) -> Bool
  • var isEmpty: Bool
  • mutating func subtract(_ other: Self)
  • func isStrictSubset(of other: Self) -> Bool
  • func isStrictSuperset(of other: Self) -> Bool
🟢
String
  • Kotlin 字符串**不可变**
  • init(data: Data, encoding: StringEncoding)
  • init(bytes: [UInt8], encoding: StringEncoding)
  • init(contentsOf: URL)
  • var capitalized: String
  • var deletingLastPathComponent: String
  • func replacingOccurrences(of search: String, with replacement: String) -> String
  • func components(separatedBy separator: String) -> [String]
  • func trimmingCharacters(in set: CharacterSet) -> String
  • var utf8Data: Data
  • func data(using: StringEncoding, allowLossyConversion: Bool = true) -> Data?
  • var utf8: [UInt8]
  • var utf16: [UInt8]
  • var unicodeScalars: [UInt8]
  • 参见 Collection
  • 由 Foundation 提供的其他字符串 API,请参见 SkipFoundation
✅ strlen
✅ strncmp
🟢
Substring
  • 参见 String
✅ SystemRandomNumberGenerator
🟡
Task
  • init(priority: TaskPriority? = nil, operation: @escaping () async throws -> Success)
  • static func detached(priority: TaskPriority? = nil, operation: @escaping () async -> Success) -> Task<Success, Failure>
  • var value: Success
  • func cancel()
  • static func yield() async
  • var isCancelled: Bool
  • static var isCancelled: Bool
  • static func checkCancellation() throws
  • static func sleep(nanoseconds duration: UInt64) async throws
  • static var min: UInt8
✅ TaskGroup
✅ ThrowingDiscardingTaskGroup
✅ ThrowingTaskGroup
✅ type(of:)
🟢
UInt8
  • static var min: UInt8
  • static var max: UInt8
  • static func random(in range: Range<UInt8>) -> UInt8
  • static func random(in range: Range<UInt8>, using gen: inout RandomNumberGenerator) -> UInt8
🟢
UInt16
  • static var min: UInt16
  • static var max: UInt16
  • static func random(in range: Range<UInt16>) -> UInt16
  • static func random(in range: Range<UInt16>, using gen: inout RandomNumberGenerator) -> UInt16
🟢
UInt32
  • static var min: UInt32
  • static var max: UInt32
  • static func random(in range: Range<UInt32>) -> UInt32
  • static func random(in range: Range<UInt32>, using gen: inout RandomNumberGenerator) -> UInt32
🟢
UInt
  • Kotlin 的 UInt 为 32 位
  • static var min: UInt
  • static var max: UInt
  • static func random(in range: Range<UInt>) -> UInt
  • static func random(in range: Range<UInt>, using gen: inout RandomNumberGenerator) -> UInt
🟢
UInt64
  • static var min: UInt64
  • static var max: UInt64
  • static func random(in range: Range<UInt64>) -> UInt64
  • static func random(in range: Range<UInt64>, using gen: inout RandomNumberGenerator) -> UInt64
✅ withDiscardingTaskGroup
✅ withTaskCancellationHandler
✅ withThrowingTaskGroup
✅ withThrowingDiscardingTaskGroup
✅ withThrowingTaskGroup

集合可能是 Swift 标准库乃至 SkipLib 中最复杂的部分。Swift 完整的集合协议让 Array、Set、Dictionary、String 等类型能够共享一组通用 API,包括迭代、map、reduce 等许多操作。

对应的 Kotlin 类型(如 List、Set、Map、String 等)并不共享同样丰富的 API。因此,SkipLib 必须在 Collections.kt 与 String.kt 中分别实现集合协议,并在 Set.kt 与 OptionSet.kt 中分别实现 SetAlgebra。

有关 SkipLib 内部集合支持的设计细节,请参阅 Collections.kt 中的说明性注释。

需要注意,Skip 的 skip.lib.Array 与 Java/Kotlin 的 kotlin.Array 并不相同。因此,如果需要把 Skip 数组传给要求 Java 风格数组的 Java API,必须按如下方式进行转换:

#if SKIP
let skipArray: skip.lib.Array<String> = ["ABC", "DEF"]
let kotlinList: kotlin.collections.List<String> = skipArray.toList()
let kotlinArray: kotlin.Array<String> = kotlinList.toTypedArray()
java.util.Arrays.sort(kotlinArray) // 与 Java 数组相同
#endif

Skip 能够为 Swift 类型的 Android 版本自动合成默认的 Codable 遵循。Android 版本的编码和解码行为与其 Swift 源类型完全一致。Skip 也支持自定义 CodingKeys,以及用于编码和解码的自定义 encode(to:) 和 init(from:) 函数。

不过,仍有一些限制:

  • 对于不遵循 RawRepresentable 的枚举,Skip 无法自动合成 Codable 遵循;你必须自行实现协议要求的函数。

  • 如果自行实现 encode 函数或 init(from:) 解码构造器并使用 CodingKeys,就必须自行声明 CodingKeys 枚举,不能依赖自动合成的枚举。

  • Array、Set 和 Dictionary 均受到完整支持,但这些类型的嵌套能力有限。例如,Skip 可以编码和解码 Array<MyCodableType> 与 Dictionary<String, MyCodableType>,但不能处理 Array<Dictionary<String, MyCodableType>>。目前支持两种容器嵌套形式:数组嵌套数组(如 Array<Array<MyCodableType>>),以及以数组为值的字典(如 Dictionary<String, Array<MyCodableType>>)。在实际开发中,其他嵌套形式并不常见。

  • 调用 decode 时,必须提供要解码的具体类型字面量。这既适用于 JSONDecoder 之类的顶层 Decoder,也适用于 KeyedDecodingContainer 等容器。以下写法可以正常工作:

    let object = try decoder.decode(MyType.self, from: jsonData)

    但以下示例无法工作:

    let type = MyType.self
    let object = try decoder.decode(type, from: jsonData)
    // T 是泛型类型
    let object = try decoder.decode(T.self, from: jsonData)

开发者通常会利用受 Decodable 约束的泛型函数来解码任意类型,因此最后这项限制影响最大。编写解码代码时必须考虑这一点;将现有代码迁移到 Skip 时,也常常需要为此重构解码逻辑。

一种缓解此限制、允许解码未知泛型类型的方法,是编写利用 Kotlin 具体化类型(reified types) 的 inline 解码函数。不过,内联函数也有自身的限制与取舍。更多信息可参阅 Kotlin 语言文档 ↗。Skip 会自动把带有 @inline(__always) 属性的 Swift 函数转换为使用具体化泛型的 Kotlin 内联函数。

例如,只要使用具体的 Response 类型调用以下函数,或从另一个 inline 函数中以泛型 Response 类型调用,它就可以在 Skip 中正常工作:

@inline(__always) public func send<R: Request, Response: Decodable>(request: R) async throws -> Response {
let data = try await download(request: request)
return try jsonDecoder.decode(Response.self, from: data)
}

它会转译为类似下面的代码:

inline suspend fun <reified R, reified Response> send(request: R): Response where R: Request, Response: Decodable {
val data = download(request = request)
return jsonDecoder.decode(Response::class, from = data)
}

skiptools/skip-lib ↗ 最近发布的 10 个版本:

完整历史记录: github.com/skiptools/skip-lib/releases ↗ — .atom 订阅源 ↗