Menu
CoddyTech

泛型函数

本课属于 Coddy Swift 学习旅程的“面向对象编程”单元。第 34 课,共 57 课。

泛型函数可以处理任何类型。尖括号中的占位符通常是 T,表示调用者使用的类型,Swift 会在每次调用时为它确定具体类型:

func firstAndLast<T>(_ items: [T]) -> [T] {
    guard let first = items.first, let last = items.last else { return [] }
    return [first, last]
}

print(firstAndLast([3, 8, 1]))
print(firstAndLast(["a", "b", "c"]))

输出:

[3, 1]
["a", "c"]

在函数内部,对 T 一无所知,因此只允许使用适用于所有类型的操作。像 T: Comparable 这样的约束可以允许更多操作,这里允许使用 < 运算符:

func largest<T: Comparable>(_ items: [T]) -> T? {
    guard var best = items.first else { return nil }
    for item in items where item > best { best = item }
    return best
}

print(largest([4, 9, 2])!)
print(largest(["pear", "apple", "zucchini"])!)

输出:

9
zucchini

泛型会保留确切的类型,这与 Any 不同。在 [Int] 上调用 largest 的结果是 Int?,因此无需类型转换就可以在算术运算中使用:

func largest<T: Comparable>(_ items: [T]) -> T? {
    items.max()
}

let top = largest([3, 7, 5]) ?? 0
print(top * 10)

输出:

70

一个函数可以有多个占位符,约束也可以指定你自己定义的协议:

protocol Scored { var score: Int { get } }
struct Player: Scored { let name: String; let score: Int }
struct Team: Scored { let score: Int }

func total<T: Scored>(_ items: [T]) -> Int {
    items.reduce(0) { $0 + $1.score }
}

func pair<A, B>(_ a: A, _ b: B) -> String { "\(a) & \(b)" }

print(total([Player(name: "a", score: 3), Player(name: "b", score: 4)]))
print(total([Team(score: 10)]))
print(pair(1, "one"))

输出:

7
10
1 & one
challenge icon

挑战

简单

编写泛型函数 countWhere(_:_:),它接收一个任意类型的数组和一个谓词 (T) -> Bool,并返回满足条件的元素数量;再编写 mostCommon(_:),它接收一个元素类型为任意 Hashable 类型的数组,并返回出现频率最高的元素(如果计数相同,则返回在数组中最先出现的元素);如果数组为空,则返回 nil。

提供的代码会读取一行逗号分隔的单词和一行数字。它会输出长度超过 3 个字符的单词数量、最常见的单词、偶数的数量以及最常见的数字。

你的代码写在 Functions.swift 中。main.swift 包含提供的输入/输出代码,不能编辑。

亲手试试

// 提供的输入/输出代码:保持原样
var input: [String] = []
while let line = readLine() { input.append(line) }
let words = input[0].split(separator: ",").map(String.init)
let numbers = input[1].split(separator: ",").map { Int($0)! }
print(countWhere(words) { $0.count > 3 })
print(mostCommon(words) ?? "none")
print(countWhere(numbers) { $0 % 2 == 0 })
print(mostCommon(numbers).map { String($0) } ?? "none")
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Swift 在线编辑器