Hashable
本课属于 Coddy Swift 学习旅程的“面向对象编程”单元。第 40 课,共 57 课。
Hashable 可以让值存储在 Set 中,或用作 Dictionary 的键。哈希是根据值计算出的数字,可用于快速查找该值。如果结构体和枚举的所有属性都符合 Hashable,只需声明遵循该协议即可:
struct Point: Hashable {
let x: Int, y: Int
}
var visited: Set<Point> = []
visited.insert(Point(x: 0, y: 0))
visited.insert(Point(x: 1, y: 0))
visited.insert(Point(x: 0, y: 0))
print(visited.count)
print(visited.contains(Point(x: 1, y: 0)))输出:
2
true可哈希的值很适合作为字典键,例如可以用来统计结构化值的出现次数:
struct Pair: Hashable {
let from: String, to: String
}
let trips = [Pair(from: "A", to: "B"), Pair(from: "B", to: "C"), Pair(from: "A", to: "B")]
var counts: [Pair: Int] = [:]
for t in trips { counts[t, default: 0] += 1 }
print(counts[Pair(from: "A", to: "B")]!)输出:
2Hashable 基于 Equatable。当 == 只比较部分属性时,哈希值也必须使用相同的属性,这在 hash(into:) 中实现。否则,两个相等的值可能会得到不同的哈希值,集合就会同时保留它们:
struct User: Hashable {
let id: Int
var name: String
static func == (lhs: User, rhs: User) -> Bool { lhs.id == rhs.id }
func hash(into hasher: inout Hasher) { hasher.combine(id) }
}
let users: Set<User> = [User(id: 1, name: "Ada"), User(id: 1, name: "Ada L."), User(id: 2, name: "Bo")]
print(users.count)输出:
2要记住这条规则:相等的值必须有相等的哈希值。哈希值会在不同的程序运行之间变化,因此不要存储或打印它们;只能通过集合和字典使用它们。
// 相等的值必须有相同的哈希值
// 不同的值通常有不同的哈希值
func hash(into hasher: inout Hasher) {
hasher.combine(id) // 恰好是 == 比较的那些属性
}挑战
简单网格上的机器人从 (0, 0) 出发,每次移动一步,方向为 U、D、L、R。让 Position(x,y)遵循 Hashable,并完成 explore(_:),使其返回三行:visited 5 cells(包括起点在内的不同位置数)、revisits 2(落在已访问过的格子上的移动次数)和 most visited (0, 0) x3(进入次数最多的格子,起点计为访问一次;如果并列,最先达到该次数的格子胜出)。
提供的代码会读取一行移动指令,并打印每一行返回内容。
你的代码写在 Position.swift 和 Functions.swift 中。main.swift 包含提供的输入/输出代码,不能编辑。
亲手试试
// 提供的输入输出代码:保持原样
var input: [String] = []
while let line = readLine() { input.append(line) }
for line in explore(input[0]) { print(line) }
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Swift 在线编辑器