闭包在方法 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) -&gt; 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: ) 函数传递到datadata[dateString],但colorIndexInt

colorIndex 在这里无关紧要。 colorIndex 只是您传递给mapValues 的函数的函数参数的名称。此时已调用mapValues,并且字典的值已被转换。

您可以将String 传递给data,因为data 字典有Strings 作为键。回想一下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 中是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用打字稿中的查找来推断类型化的 mapValues?

reduce() 方法在 Java 8 中是如何工作的?

译理解JavaScript闭包——新手指南

ES6 等价于 lodash _.mapValues

js进阶之闭包

typeof 方法在 JavaScript 中是如何工作的? [复制]