【问题标题】:How does the Swift Dictionary subscript disambiguate Int keys and indices?Swift Dictionary 下标如何消除 Int 键和索引的歧义?
【发布时间】:2018-05-23 07:42:32
【问题描述】:

目前我正在研究一种数据结构,旨在唯一地存储键值对并保持它们按键排序。从本质上讲,它是一个排序字典,因此我希望尽可能多地保留 Swift 的 Collection 和 Dictionary 语义。

在文档和 Swift 源代码中(尽我所能),字典有两个下标。一种是最常用的subscript by key (Github source)

extension Dictionary {
  ...
  public subscript(key: Key) -> Value? {
    @inline(__always)
    get {
      return _variantBuffer.maybeGet(key)
    }
    set(newValue) {
      if let x = newValue {
        // FIXME(performance): this loads and discards the old value.
        _variantBuffer.updateValue(x, forKey: key)
      }
      else {
        // FIXME(performance): this loads and discards the old value.
        removeValue(forKey: key)
      }
    }
  }
  ...
}

第二个是subscript by position/index (Github) source),作为其符合 Collection 协议的一部分:

extension Dictionary: Collection {
  ...
  public subscript(position: Index) -> Element {
    return _variantBuffer.assertingGet(position)
  }
  ...
}

当将这些与由 Int 以外的其他内容作为键的字典一起使用时,它们的行为与预期完全一样,因为下标由不同的参数类型区分,即:StringInt

let stringKeys = ["One": 1, "Two": 2, "Three": 3]
stringKeys["One"]   // 1
stringKeys[1]       // ("Two", 2)

Ints 用作键时,根据需要使用键下标。

let intKeys = [1: "One, 2: "Two, 3: "Three"]
intKeys[1]   // "One"

Dictionary 类型是如何做到这一点的?在我看来,下标的 IndexKey 参数都是 Int 并且编译器不应该知道哪个是预期的。事实上,当我为我的自定义字典实现相同的下标时,当我使用 Int 键对其进行测试时,编译器会给出确切的错误——“‘下标’的歧义使用”。

起初我想知道是否一个是协议扩展中提供的默认值并被更具体的实现覆盖,但据我所知,情况并非如此。我唯一的其他理论是Index 是除“Int”之外的其他类型,因此它仍然是明确的,但我找不到任何可以证实这一点的方法。任何人都可以对此有所了解吗?除了我的迫切需要之外,我还想了解 Swift 中的一些非常聪明的行为。

感谢大家的阅读和帮助!

【问题讨论】:

    标签: swift dictionary ambiguous subscript


    【解决方案1】:

    我唯一的其他理论是 Index 属于其他类型而不是“Int”,因此它仍然是明确的,但我找不到任何可以证实这一点的方法。

    就是这样。 Dictionary 有两个下标方法:

    public subscript(key: Dictionary.Key) -> Dictionary.Value?
    public subscript(position: Dictionary<Key, Value>.Index) -> Dictionary.Element { get }
    

    第一个接受一个键并返回一个(可选)值, 第二个需要Dictionary.Index (source code) 并返回一个(可选)Dictionary.Element, 即一个键值对。 示例:

    let d : Dictionary = [1 : "one"]
    if let idx = d.index(forKey: 1) {
        print(String(reflecting: type(of: idx))) // Swift.Dictionary<Swift.Int, Swift.String>.Index
        let kv = d[idx]
        print(String(reflecting: type(of: kv)))  // (key: Swift.Int, value: Swift.String)
    }
    

    Dictionary.Index也用于其他方法如

    public var startIndex: Dictionary<Key, Value>.Index { get }
    public var endIndex: Dictionary<Key, Value>.Index { get }
    public func index(where predicate: ((key: Key, value: Value)) throws -> Bool) rethrows -> Dictionary<Key, Value>.Index?
    

    它们是Collection 协议的一部分。

    一般情况下,Collection 的关联 Index 类型不是 一定是Int,另一个例子是String,它有 拥有String.Index 类型。

    【讨论】:

      猜你喜欢
      • 2017-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多