Swift 字典

字典(Dictionary)是 Swift 的另一个核心集合类型——键值对映射。它相当于 Python 的 dict、Java 的 HashMap、JS 的 Object。配置项、用户信息、缓存——任何"用名字查数据"的场景都适合用字典。

1. 创建

// 字典:键值对,key 唯一,key 必须是 Hashable
var scores: [String: Int] = [
    "小明": 90,
    "小红": 85,
    "小张": 78,
]

// 类型推断
var cache = ["a": 1, "b": 2]    // [String: Int]

// 空字典
var empty1: [String: Int] = [:]
var empty2 = [String: Int]()

print(scores.count)             // 3
print(scores.isEmpty)           // false

几个关键点:

2. 查询(返回 Optional)

这是 Swift 字典和大多数语言最大的不同——取值返回 Optional,因为 key 可能不存在:

// 查询:返回 Optional(键不存在时返回 nil)
let scores = ["小明": 90, "小红": 85]
print(scores["小明"] ?? -1)     // 90
print(scores["小张"] ?? -1)     // -1(不存在)

// 强制解包(只在确定存在时用)
// print(scores["小明"]!)        // 90,但不存在会崩溃

// 默认值:用 ?? 或下标 default
let score = scores["小张", default: 60]
print(score)                    // 60(不存在时给默认)

// 包含某个 key
if scores.keys.contains("小明") {
    print("有小明")
}
// 更优雅:
if scores["小明"] != nil {
    print("有小明")
}

这条设计避免了"key 不存在时返回 null/undefined,后续操作全崩"的经典 bug。配合 ?? 给默认值,代码既安全又简洁。

3. 增删改

var scores: [String: Int] = ["小明": 90]

// 新增/修改(同一个语法)
scores["小红"] = 85            // 新增
scores["小明"] = 95            // 修改(已存在)
print(scores)

// updateValue:返回旧值(Optional)
if let old = scores.updateValue(100, forKey: "小明") {
    print("小明的旧分: \(old)")  // 95
}

// 删除
scores["小张"] = 70
scores["小张"] = nil           // 设为 nil 等于删除
print(scores)

// removeValue:返回被删的值
if let removed = scores.removeValue(forKey: "小红") {
    print("删除了 \(removed)")
}

// 清空
scores.removeAll()

新增和修改用同一个语法(dict[key] = value)——key 不存在就新增,存在就覆盖。删除有两种:设为 nil 或 removeValue(forKey:)。后者返回被删的值。

4. 遍历

let scores = ["小明": 90, "小红": 85, "小张": 78]

// 遍历键值对(顺序不保证!字典无序)
for (name, score) in scores {
    print("\(name): \(score)")
}

// 只遍历 key
for name in scores.keys {
    print(name)
}

// 只遍历 value
for score in scores.values {
    print(score)
}

// 想要排序的遍历,先排序
for name in scores.keys.sorted() {
    print("\(name): \(scores[name]!)")
}

// 转数组
let allKeys = Array(scores.keys)
let allValues = Array(scores.values)

遍历解构 (key, value) 是最常用模式。注意顺序不保证,需要排序先 sorted().keys.values 是懒计算集合,转 Array 才能多次遍历。

5. 分组与 mapValues(超实用)

Swift 标准库提供了几个超实用的字典构造工具:

// group:按某条件把数组分组
let students = [
    ("小明", "一班"), ("小红", "一班"),
    ("小张", "二班"), ("小李", "二班"), ("小王", "三班"),
]

// 按班级分组
let byClass = Dictionary(grouping: students, by: { $0.1 })
print(byClass)
// ["一班": [(小明, 一班), (小红, 一班)],
//  "二班": [(小张, 二班), (小李, 二班)],
//  "三班": [(小王, 三班)]]

// 统计每个班级人数
let counts = Dictionary(grouping: students, by: { $0.1 })
    .mapValues { $0.count }
print(counts)                  // ["一班": 2, "二班": 2, "三班": 1]

// mapValues:只变换 value,保留 key
let doubled = ["a": 1, "b": 2].mapValues { $0 * 2 }
print(doubled)                 // ["a": 2, "b": 4]

Dictionary(grouping:by:) 是处理"分类"问题的神器——按班级分组、按日期分组、按状态分组,一行搞定。mapValues 只变换值保留键,常用于"修改配置但不改 key"。

6. 与 JSON 互转

字典和 JSON 是天然的一对——键值对结构完全对应。Swift 标准库提供 JSONSerialization 做基本转换:

import Foundation

// 字典 → JSON
let user: [String: Any] = [
    "name": "小明",
    "age": 18,
    "isVip": true,
]

if let data = try? JSONSerialization.data(withJSONObject: user, options: .prettyPrinted),
   let json = String(data: data, encoding: .utf8) {
    print(json)
}

// JSON → 字典
let jsonString = """
{"name": "小红", "age": 20}
"""
let data = jsonString.data(using: .utf8)!
if let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
    print(dict["name"] ?? "")   // 小红
}

// 实战推荐:用 Codable 协议把 JSON 解成 struct,后面专章讲

但实战中更推荐用 Codable 协议——把 JSON 直接解码成 struct,类型安全、自动处理可选字段、代码极简。这在后续"进阶"章会讲。

7. 性能特点

8. 常见陷阱

小结

字典 = 键值对 + Optional 返回 + 增删改查 + grouping/mapValues + JSON 互转。和数组搭配,日常 90% 的数据组织都能搞定。下一篇讲 Swift 的类型系统核心——类与结构体

← 上一篇 Swift 数组

下一篇 Swift 类与结构体

✈️💬