在 Swift 中,map 是一种高阶函数,适用于集合类型(如数组、字典等)、Optional、Result 等。它的主要功能是将一个集合或值中的每个元素通过一个闭包进行转换,并生成一个新的集合或值。
map 的基本用法
1、适用于数组
map 遍历数组的每个元素,对其进行变换,并返回一个新数组。
示例:将整数数组转为字符串数组
let numbers = [1, 2, 3, 4, 5]
let strings = numbers.map { "\($0)" }
print(strings) // ["1", "2", "3", "4", "5"]
2、适用于字典
对于字典,map 可以作用于每个键值对。
示例:对字典的值进行变换
let dictionary = ["a": 1, "b": 2, "c": 3]
let doubledValues = dictionary.map { key, value in (key, value * 2) }
print(doubledValues) // [("a", 2), ("b", 4), ("c", 6)]
dictionary.map 会遍历字典中的每个键值对 (key, value)。
闭包的返回值会被收集到一个新的数组中。
在这个例子中,闭包返回了 (key, value * 2),即一个元组 (String, Int)。
如果希望保留字典类型,可以使用 mapValues 方法,它仅对值进行变换,同时保留键值对结构。
let dictionary = ["a": 1, "b": 2, "c": 3]
// 使用 mapValues 只对值进行变换
let doubledValues = dictionary.mapValues { $0 * 2 }
print(doubledValues) // ["a": 2, "b": 4, "c": 6]
3、适用于 Optional
当 Optional 有值时,map 对其进行变换;如果为 nil,则什么都不做。
示例:将 Optional 的值进行转换
let number: Int? = 42
let doubled = number.map { $0 * 2 }
print(doubled) // Optional(84)
let noValue: Int? = nil
let result = noValue.map { $0 * 2 }
print(result) // nil
map 和 flatMap 的区别
map:返回的是嵌套结构(例如数组中的数组,或可选值中的可选值)。
flatMap:会自动展开嵌套结构。
示例:使用数组中的数组
let nested = [[1, 2], [3, 4], [5, 6]]
// 使用 map
let mapped = nested.map { $0 }
print(mapped) // [[1, 2], [3, 4], [5, 6]]
// 使用 flatMap
let flatMapped = nested.flatMap { $0 }
print(flatMapped) // [1, 2, 3, 4, 5, 6]
示例:使用 Optional 嵌套
let number: Int?? = 42
let mapped = number.map { $0 }
print(mapped) // Optional(Optional(42))
let flatMapped = number.flatMap { $0 }
print(flatMapped) // Optional(42)
适用于其他类型
1、Result
map 只对 Result 的成功值进行转换,而忽略失败的情况。
示例:
let successResult: Result<Int, Error> = .success(42)
let doubledResult = successResult.map { $0 * 2 }
print(doubledResult) // .success(84)
let failureResult: Result<Int, Error> = .failure(NSError(domain: "", code: 1, userInfo: nil))
let newResult = failureResult.map { $0 * 2 }
print(newResult) // .failure(Error)
2、自定义类型
只要类型实现了 map,它就可以使用,比如某些第三方框架的类型(如 Promise、Future)。
示例:定义一个简单的容器类型
先定义一个容器类型 Box,它可以包含任意类型的值。
struct Box<T> {
let value: T
// 实现 map 方法
func map<U>(_ transform: (T) -> U) -> Box<U> {
// 对内部值应用 transform 函数,并返回一个新容器
return Box<U>(value: transform(value))
}
}
enum Future<T> {
case success(T)
case failure(Error)
// 实现 map 方法
func map<U>(_ transform: (T) -> U) -> Future<U> {
switch self {
case .success(let value):
return .success(transform(value))
case .failure(let error):
return .failure(error)
}
}
}
使用方法:
let future: Future<Int> = .success(42)
// 使用 map 将 Future 的成功值转换
let newFuture = future.map { $0 * 2 } // Future.success(84)
print(newFuture)
在这个例子中,map 保留了 Future 的结构,只对其中的值进行了操作。
map 的约定和特性
为了符合函数式编程的范式,map 通常具有以下特性:
不改变容器本身:只变换容器中的值。
纯函数:map 不引入副作用,结果仅依赖于输入值。
可组合性:多个 map 可以连续调用,形成链式操作。
例如:
let box = Box(value: 10)
let newBox = box
.map { $0 + 5 } // Box(value: 15)
.map { $0 * 2 } // Box(value: 30)
print(newBox.value) // 输出: 30
总结
map 的核心思想是:“保持容器结构不变,对容器中的每个元素进行映射变换。”
它是函数式编程中的重要工具,让代码更简洁、清晰,避免了大量的循环和条件判断。