闭包在方法 mapValues 中是如何工作的?
Posted
技术标签:
【中文标题】闭包在方法 mapValues 中是如何工作的?【英文标题】:How does the closure work in the method mapValues? 【发布时间】:2020-08-04 00:34:02 【问题描述】:我试图了解mapValues 方法在Calendar Heatmap 的以下代码中的工作原理。
-
首先,函数加载字典:
private func readHeatmap() -> [String: Int]?
guard let url = Bundle.main.url(forResource: "heatmap", withExtension: "plist") else return nil
return NSDictionary(contentsOf: url) as? [String: Int]
heatmap.plist 是这样的键/值列表:
<key>2019.5.3</key>
<integer>3</integer>
<key>2019.5.5</key>
<integer>4</integer>
<key>2019.5.7</key>
<integer>3</integer>
-
使用上述函数初始化属性:
lazy var data: [String: UIColor] =
guard let data = readHeatmap() else return [:]
return data.mapValues (colorIndex) -> UIColor in
switch colorIndex
case 0:
return UIColor(named: "color1")!
case 1:
return UIColor(named: "color2")!
case 2:
return UIColor(named: "color3")!
case 3:
return UIColor(named: "color4")!
default:
return UIColor(named: "color5")!
()
-
最后,上面定义的
data
属性用在下面的函数中:
func colorFor(dateComponents: DateComponents) -> UIColor
guard let year = dateComponents.year,
let month = dateComponents.month,
let day = dateComponents.day else return .clear
let dateString = "\(year).\(month).\(day)"
return data[dateString] ?? UIColor(named: "color6")!
Apple 的文档指出 mapValues
返回一个字典“包含该字典的键以及由给定闭包转换的值。”
我的问题是,传递给data.mapValues (colorIndex) -> UIColor in
闭包的值colorIndex
到底是什么?是来自heatmap.plist
吗?我很困惑 String
是如何从 colorFor(dateComponents: )
函数传递到 date
, date[dateString] 的,但 colorIndex
是 Int。
【问题讨论】:
【参考方案1】:原来data
是这样的:
"2019.5.3" : 3
"2019.5.5" : 4
"2019.5.7" : 3
假设您执行了data.mapValues(f)
,其中f
是一个函数,生成的字典将如下所示:
"2019.5.3" : f(3)
"2019.5.5" : f(4)
"2019.5.7" : f(3)
所以现在,字典的值类型变为f
的返回类型,而键类型保持不变。
传递给闭包的值
colorIndex
究竟是什么?
这是data
中的每个值。每个值都会被传入闭包一次。
为了更清楚地看到这一点,我编写了一种可能的方式来实现mapValues
:
extension Dictionary
func myMapValues<T>(_ transform: (Value) throws -> T) rethrows -> [Key: T]
var retVal = [Key: T]()
for entry in self
retVal[entry.key] = try transform(entry.value)
return retVal
是来自 heatmap.plist 吗?
间接地,是的。局部变量data
([String: Int]
)的内容原本来自heatmap.plist
,但是mapValues
直接对已经从文件中读取的data
进行操作。
我很困惑如何将字符串从
colorFor(dateComponents: )
函数传递到data
、data[dateString]
,但colorIndex
是Int
。
colorIndex
在这里无关紧要。 colorIndex
只是您传递给mapValues
的函数的函数参数的名称。此时已调用mapValues
,并且字典的值已被转换。
您可以将String
传递给data
,因为data
字典有String
s 作为键。回想一下mapValues
不会更改密钥类型。请注意,此 data
与局部变量 data
不同。我说的是lazy
属性data
,类型为[String: UIColor]
。
【讨论】:
感谢您的回答。这是否意味着原来的[key: value]
从"2019.5.5" : 4
转换为"2019.5.5" : UIColor(named: "color5")
?如果这里data
属性的目的是输入一些下标data[dateString]
,并返回一个对应的UIColor
,我不确定这里的plist
是干什么用的。
@Kevvv 回复:你的第一个问题,是的。回复:“我不确定这里的 plist 是干什么用的。” plist 是为了提供后期绑定。当然,您可以在源代码中硬编码[String: UIColor]
字典,但要更改其内容,您必须重新编译。将数据放入文件中可以轻松进行更改。
你可以直接返回try .init(uniqueKeysWithValues: zip(keys, values.map(transform)))
说操作顺序是否正确 1) 写入 plist "2020.8.3" : 3
2) 字典被转换为相应的颜色 "2020.8.3" :UIColor(named: "color4")
和 3) data["2020.8.3"]
@Kevvv 第 1 步应该是从 plist 中读取字典。另请注意,由于 data
是惰性的,因此步骤 1 和 2 只会执行一次,但每次调用 colorFor
时都会执行步骤 3。以上是关于闭包在方法 mapValues 中是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章