【问题标题】:Reducing a Swift array to [Int:Int?] with nil initializer is empty使用 nil 初始化器将 Swift 数组减少为 [Int:Int?] 是空的
【发布时间】:2020-01-18 20:09:42
【问题描述】:

为什么将数组缩减为以键为数组值、值为 nil 的散列会得到空结果?

[1,2,3].reduce(into: [Int:Int?](), { $0[$1] = nil })
[1,2,3].reduce(into: [Int:Int?](), { $0[$1] = 1 })

这两个都应该有 3 个条目,对吧?

【问题讨论】:

  • 将字典值设置为 nil 与删除它相同。所以你实际上从来没有为这些键设置任何值
  • 呃,你是对的!解决此问题的方法是像Set<K>, Dictionary<K,V> 一样单独存储您的密钥,然后将字典中缺少的任何内容视为 nil
  • @ElectricPenguin 这完全没有必要。看我的回答(马上就到)

标签: arrays swift reduce


【解决方案1】:

在 Swift 中,像您在问题中所做的那样将字典值设置为 nil 会完全从字典中删除该值。但是,对此有一些奇怪的警告。

在您的示例中,您使用Dictionary 类型为[Int:Int?]

var dictionary: [Int:Int?] = [1: 1, 2: 1, 3: 1]

通过以下方式将值设置为 nil 会删除它:

dictionary[1] = nil

将值设置为nil 类型为Int? 将改为分配nil

dictionary[1] = nil as Int?

同样,使用updateValue(_:forKey:) 函数也可以:

dictionary.updateValue(nil, forKey: 1)

在执行上述任一操作后打印字典将显示以下内容:

[1: nil, 2: Optional(1), 3: Optional(1)]

所以行为有点奇怪,但有可能达到您的预期结果。我真的不推荐它,因为它很不自然。不过有可能。

【讨论】:

    【解决方案2】:

    这种行为实际上一点也不奇怪,如果您了解 Swift 字典和可选项的一些基本特性,这是一个非常自然的结果。

    嵌套选项

    首先,可选项是可组合的。你可以有嵌套的选项,比如Optional<Optional<Int>>(又名Int??)。像这样的嵌套选项可能有三个值。为了说明它们的区别,想象一下array.first的结果,其中array的类型为Array<Optional<Optional<Int>>

    1. Optional.some(Optional.some(someWrappedValue)),这只是“非零”情况,有效载荷为someWrappedValue。在array.first 的上下文中,这意味着数组是非空的,并且第一个元素是非零值someWrappedValueInt 类型)。

    2. Optional.some(Optional.none),这是一个包含nil 的非零可选。在array.first的上下文中,这意味着十个数组是非空的,第一个元素本身就是nil

    3. Optional.none,这只是一个nil 可选。在array.first 的上下文中,这意味着数组是空的,并且没有第一个元素。

    请注意案例 2 和案例 3 之间的区别。沿链“找到” nil 的“位置”具有语义差异。 Optional.none (a.k.a. nil) 表示没有元素,这在语义上与 Optional.some(Optional.none) 不同,这意味着有 are 个元素,但其中第一个实际上是 nil

    nil的确切含义

    其次,nilOptional<T>.none 的简写,其中T 是从上下文中推断出来的。例如,这就是为什么let x = nil 是非法的,因为类型推断系统不知道T 的什么值是合适的。

    请注意,nil 本身被推断为处于“最早”(“最外层”)可选级别的 none。 (案例3,在上面的列表中)

    通过字典下标分配 nil

    第三,通过下标将nil 分配给字典会删除给定键的值。

    把它放在一起

    鉴于这三点,我们可以考虑您的示例。字典的下标比字典的Value 泛型类型“多一层可选”。例如。对于[Int: Int]类型的dict,下标运算符的返回类型为V?,对应的可以赋值Int?

    现在考虑你的字典,类型为[Int: Int?]。下标接受/返回Int??。让我们像以前一样在上下文中考虑三种可能的情况:

    1. 分配Optional.some(Optional.some(someWrappedValue)) 类型的值会使dict 为键存储someWrappedValue 的值,作为Int?。这就是你写$0[$1] = 1 时发生的事情(Swift 隐含地将1 提升为Optional.some(Optional.some(1))

    2. 分配 Optional.some(Optional.none) 类型的值会使 dict 为键存储 nil 的值,作为 Int?。这是您缺少的部分。

    3. 分配 Optional.none 类型的值会使 dict 删除键可能存在的任何值。这就是你写$0[$1] = nil

    4. 时发生的事情

    因此,要使此代码给出您设计的结果,您需要提供第二种类型的值。你可以这样做:

    [1,2,3].reduce(into: [Int:Int?]()) { $0[$1] = Optional.some(nil) }
    

    【讨论】:

      猜你喜欢
      • 2019-03-03
      • 2022-06-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-29
      • 2016-11-01
      • 1970-01-01
      • 2014-04-23
      相关资源
      最近更新 更多