Swift 通过范型提供了非常强大的抽象能力。Swift 编译器通过 MySwiftFunc<T> 生成可以为 T 执行的代码块。生成的代码块包含一个函数指针列表和一个包含 T 容器作为参数。MySwiftFunc<Int> 和 MySwiftFunc<String> 的不同表现,是通过传递不同的函数列表和容器大小来决定的。一个范型例子:
Swift 中类总是采用引用计数。 Swift 编译器会在每次对象被访问时插入增加引用计数的代码。例如,考虑一个通过使用类实现遍历链表的例子。遍历链表是通过从一个节点到下一个节点移动引用实现: elem = elem.next。每次我们移动这个引用, Swift 将会增加 next 对象的引用计数,并且减少前一个对象的引用计数。这样的引用计数方法成本很高,但只要我们使用 Swift 的类就无法避免。
class A {
var aProperty: [Int]
func doSomething() { ... }
dynamic doSomethingElse() { ... }
}
class B: A {
override var aProperty {
get { ... }
set { ... }
}
override func doSomething() { ... }
}
func usingAnA(_ a: A) {
a.doSomething()
a.aProperty = ...
}
final class C {
// class 'C' 中所有声明的都不能被重写
// No declarations in class 'C' can be overridden.
var array1: [Int]
func doSomething() { ... }
}
class D {
// array1 不能被计算属性重写
final var array1: [Int] // 'array1' cannot be overridden by a computed property.
// array2 能被计算属性重写
var array2: [Int] // 'array2' *can* be overridden by a computed property.
}
func usingC(_ c: C) {
// 访问 C.array1 不会经过动态派发
c.array1[i] = ... // Can directly access C.array without going through dynamic dispatch.
// 会直接调用 C.doSomething 不会经过虚函数表调用
c.doSomething() = ... // Can directly call C.doSomething without going through virtual dispatch.
}
func usingD(_ d: D) {
// 直接访问 D.array1 不经过动态派发
d.array1[i] = ... // Can directly access D.array1 without going through dynamic dispatch.
// 经过动态派发访问 D.array2
d.array2[i] = ... // Will access D.array2 through dynamic dispatch.
}
private class E {
func doSomething() { ... }
}
class F {
fileprivate var myPrivateVar: Int
}
func usingE(_ e: E) {
/**
该文件内没有子类存在
编译器可以移除 doSomething 的虚表调用,并直接调用 E 的 doSomething 方法
*/
e.doSomething() // There is no sub class in the file that declares this class.
// The compiler can remove virtual calls to doSomething()
// and directly call E's doSomething method.
}
func usingF(_ f: F) -> Int {
return f.myPrivateVar
}
// Don't use a class here.
struct PhonebookEntry {
var name: String
var number: [Int]
}
var a: [PhonebookEntry]
class C { ... }
var a: ContiguousArray<C> = [C(...), C(...), ..., C(...)]
var c: [Int] = [ ... ]
var d = c // No copy will occur here.
d.append(2) // A copy *does* occur here.
func append_one(_ a: [Int]) -> [Int] {
var a = a
a.append(1)
return a
}
var a = [1, 2, 3]
a = append_one(a)
func append_one_in_place(a: inout [Int]) {
a.append(1)
}
var a = [1, 2, 3]
append_one_in_place(&a)
a: [Int]
b: [Int]
c: [Int]
// Precondition: for all a[i], b[i]: a[i] + b[i] either does not overflow,
// or the result of wrapping is desired.
for i in 0 ... n {
c[i] = a[i] &+ b[i]
}
class MySwiftFunc<T> { ... }
// 生成为 Int 工作的代码
MySwiftFunc<Int> X // Will emit code that works with Int...
// 生成为 String 工作的代码
MySwiftFunc<String> Y // ... as well as String.
class MyStack<T> {
func push(_ element: T) { ... }
func pop() -> T { ... }
}
func myAlgorithm<T>(_ a: [T], length: Int) { ... }
// The compiler can specialize code of MyStack<Int>
// 编译器会为范型 MyStack<Int> 生成特定代码
var stackOfInts: MyStack<Int>
// Use stack of ints.
for i in ... {
stack.push(...)
stack.pop(...)
}
var arrayOfInts: [Int]
// The compiler can emit a specialized version of 'myAlgorithm' targeted for
// [Int]' types.
// 编译器会生成针对 [Int] 版本的函数
myAlgorithm(arrayOfInts, arrayOfInts.length)
protocol P {}
struct Node: P {
var left, right: P?
}
struct Tree {
var node: P?
init() { ... }
}
struct Tree: P {
var node: [P?]
init() {
node = [thing]
}
}
final class Ref<T> {
var val: T
init(_ v: T) { val = v }
}
struct Box<T> {
var ref: Ref<T>
init(_ x: T) { ref = Ref(x) }
var value: T {
get { return ref.val }
set {
if !isKnownUniquelyReferenced(&ref) {
ref = Ref(newValue)
return
}
ref.val = newValue
}
}
}
final class Node {
var next: Node?
var data: Int
...
}
// The call to ``withExtendedLifetime(Head)`` makes sure that the lifetime of
// Head is guaranteed to extend over the region of code that uses Unmanaged
// references. Because there exists a reference to Head for the duration
// of the scope and we don't modify the list of ``Node``s there also exist a
// reference through the chain of ``Head.next``, ``Head.next.next``, ...
// instances.
withExtendedLifetime(Head) {
// Create an Unmanaged reference.
var Ref: Unmanaged<Node> = Unmanaged.passUnretained(Head)
// Use the unmanaged reference in a call/variable access. The use of
// _withUnsafeGuaranteedRef allows the compiler to remove the ultimate
// retain/release across the call/access.
while let Next = Ref._withUnsafeGuaranteedRef { $0.next } {
...
Ref = Unmanaged.passUnretained(Next)
}
}
protocol Pingable: AnyObject { func ping() -> Int }
let f: () -> () = { ... } // Escaping closure
// Contrasted with:
({ ... })() // Non Escaping closure
x.map { ... } // Non Escaping closure