定义

-泛型可以将类型参数化,提高代码复用率,减少代码量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func swapValues<T>(_ a: inout T, _ b: inout T) {
(a, b) = (b, a)
}
var i1 = 10
var i2 = 20
swapValues(&i1, &i2)
var d1 = 10.0
var d2 = 20.0
swapValues(&d1, &d2)

struct Date {
var year = 0, month = 0, day = 0
}
var dd1 = Date(year: 2011, month: 9, day: 10)
var dd2 = Date(year: 2012, month: 10, day: 11)
swapValues(&dd1, &dd2)
  • 泛型函数赋值给变量
    1
    2
    func test<T1, T2>(_ t1: T1, _ t2: T2) {}
    var fn: (Int, Double) -> () = test

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Stack<E> {
var elements = [E]()
func push(_ element: E) { elements.append(element) }
func pop() -> E { elements.removeLast() }
func top() -> E { elements.last! }
func size() -> Int { elements.count }
}

class SubStack<E> : Stack<E> {}

var stack = Stack<Int>()
stack.push(11)
stack.push(22)
stack.push(33)
print(stack.top()) // 33
print(stack.pop()) // 33
print(stack.pop()) // 22
print(stack.pop()) // 11
print(stack.size()) // 0

struct Stack<E> {
var elements = [E]()
mutating func push(_ element: E) { elements.append(element) }
mutating func pop() -> E { elements.removeLast() }
func top() -> E { elements.last! }
func size() -> Int { elements.count }
}

enum Score<T> {
case point(T)
case grade(String)
}
let score0 = Score<Int>.point(100)
let score1 = Score.point(99)
let score2 = Score.point(99.5)
let score3 = Score<Int>.grade("A")

关联类型(Associated Type)

  • 关联类型的作用:给协议中用到的类型定义一个占位名称
  • 协议中可以拥有多个关联类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
protocol Stackable {
associatedtype Element // 关联类型
mutating func push(_ element: Element)
mutating func pop() -> Element
func top() -> Element
func size() -> Int
}

class Stack<E> : Stackable {
// typealias Element = E
var elements = [E]()
func push(_ element: E) {
elements.append(element)
}
func pop() -> E { elements.removeLast() }
func top() -> E { elements.last! }
func size() -> Int { elements.count }
}

class StringStack : Stackable {
// 给关联类型设定真实类型
// typealias Element = String
var elements = [String]()
func push(_ element: String) { elements.append(element) }
func pop() -> String { elements.removeLast() }
func top() -> String { elements.last! }
func size() -> Int { elements.count }
}
var ss = StringStack()
ss.push("Jack")
ss.push("Rose")

类型约束

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protocol Runnable { }
class Person { }
func swapValues<T : Person & Runnable>(_ a: inout T, _ b: inout T) {
(a, b) = (b, a)
}

protocol Stackable {
associatedtype Element: Equatable
}

class Stack<E : Equatable> : Stackable { typealias Element = E }

func equal<S1: Stackable, S2: Stackable>(_ s1: S1, _ s2: S2) -> Bool
where S1.Element ` S2.Element, S1.Element : Hashable {
return false
}
var stack1 = Stack<Int>()
var stack2 = Stack<String>()
// error: requires the types 'Int' and 'String' be equivalent
equal(stack1, stack2)

协议类型的注意点

1
2
3
4
5
6
7
8
9
10
11
protocol Runnable {}
class Person : Runnable {}
class Car : Runnable {}
func get(_ type: Int) -> Runnable {
if type ` 0 {
return Person()
}
return Car()
}
var r1 = get(0)
var r2 = get(1)
  • 如果协议中有 associatedtype
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    protocol Runnable {
    associatedtype Speed
    var speed: Speed { get }
    }

    class Person : Runnable {
    var speed: Double { 0.0 }
    }

    class Car : Runnable {
    var speed: Int { 0 }
    }

泛型解决

  • 解决方案①:使用泛型
    1
    2
    3
    4
    5
    6
    7
    8
    func get<T : Runnable>(_ type: Int) -> T {
    if type ` 0 {
    return Person() as! T
    }
    return Car() as! T
    }
    var r1: Person = get(0)
    var r2: Car = get(1)

不透明类型(Opaque Type)

  • 解决方案②:使用some关键字声明一个不透明类型
    1
    2
    3
    func get(_ type: Int) -> some Runnable { Car() }
    var r1 = get(0)
    var r2 = get(1)
  • some限制只能返回一种类型

some

  • some除了用在返回值类型上,一般还可以用在属性类型上
    1
    2
    3
    4
    5
    6
    7
    protocol Runnable { associatedtype Speed }
    class Dog : Runnable { typealias Speed = Double }
    class Person {
    var pet: some Runnable {
    return Dog()
    }
    }

可选项的本质

  • 可选项的本质是enum类型
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    public enum Optional<Wrapped> : ExpressibleByNilLiteral {
    case none
    case some(Wrapped)
    public init(_ some: Wrapped)
    }

    var age: Int? = 10
    var age0: Optional<Int> = Optional<Int>.some(10)
    var age1: Optional = .some(10)
    var age2 = Optional.some(10)
    var age3 = Optional(10)
    age = nil
    age3 = .none

    var age: Int? = nil
    var age0 = Optional<Int>.none
    var age1: Optional<Int> = .none

    var age: Int? = .none
    age = 10
    age = .some(20)
    age = nil

    switch age {
    case let v?:
    print("some", v)
    case nil:
    print("none")
    }

    switch age {
    case let .some(v):
    print("some", v)
    case .none:
    print("none")
    }

    // 另一示例
    var age_: Int? = 10
    var age: Int?? = age_
    age = nil

    var age0 = Optional.some(Optional.some(10))
    age0 = .none
    var age1: Optional<Optional> = .some(.some(10))
    age1 = .none

    var age: Int?? = 10
    var age0: Optional<Optional> = 10

参考

  • 李明杰老师课件