Swift Dictionary下标如何消除Int键和索引的歧义?

时间:2017-12-09 03:01:28

标签: swift dictionary ambiguous subscript

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

在文档和Swift源代码中(尽我所能),Dictionaries有两个下标。一个是最常用的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之外的其他内容键入的词典时,它们的行为完全符合预期,因为下标由不同的参数类型区分,即:String vs Int

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

Int用作键时,键盘下标将根据需要使用。

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

Dictionary类型如何实现这一目标?在我看来,下标的IndexKey参数都是Int,并且编译器不应该知道哪些是预期的。实际上,当我为自定义词典实现相同的下标时,编译器会给出错误 - “模糊地使用'下标'” - 当我使用Int键进行测试时。

首先,我想知道一个是否是协议扩展中提供的默认值,并被更具体的实现覆盖,但从我上面所说的并非如此。我唯一的另一个理论是Index是除了'Int`以外的其他类型,因此它仍然是明确的,但我找不到任何证实这一点的方法。任何人都可以对此有所了解吗?除了我的直接需求之外,我想了解Swift中的一个非常聪明的行为。

感谢大家的阅读和帮助!

1 个答案:

答案 0 :(得分:1)

  

我唯一的另一个理论是,索引是“Int”以外的其他类型,因此它仍然是明确的,但我无法找到确认这一点的任何东西。

这就是它的确切方式。 Dictionary有两个下标方法:

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

第一个接受一个键并返回一个(可选)值, 第二个需要Dictionary.Indexsource 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协议的一部分。

通常,Index的关联Collection类型不是 必须是Int,另一个例子是String 拥有String.Index类型。