【问题标题】:How to apply an extension to only some specializations of a generic type?如何仅将扩展应用于泛型类型的某些特化?
【发布时间】:2014-08-15 06:57:34
【问题描述】:

有没有办法将扩展应用于泛型类型以使其符合协议,而该扩展仅对泛型类型的某些特化有效?

例如,考虑这个协议,它返回一个字典,计算符合协议的实例包含的值的频率:

// a type conforming to this protocol should return a dictionary
// which counts the frequencies of values contained by the type instance
protocol ConvertibleToFrequencyDictionary {
   typealias ItemType
   func dictionaryCountingFrequencies<ItemType:Hashable>() -> Dictionary<ItemType,Int>
}

因为被计数的值必须作为字典的键,所以这些值必须是符合 Hashable 的类型。这通过泛型dictionaryCountingFrequencies 方法定义的类型约束来表示。 (我没有看到任何直接在关联类型上定义类型约束的方法,例如,在“typealias”声明中。)

现在考虑 Array 上的这个扩展,旨在使其符合协议:

extension Array : ConvertibleToFrequencyDictionary {
  typealias ItemType=Element
  func dictionaryCountingFrequencies<ItemType:Hashable>() -> Dictionary<ItemType,Int> {
    var valueToCount = Dictionary<ItemType,Int>()
    for item in self {
      if let existingCount = valueToCount[item] {
        valueToCount.updateValue(value: existingCount + 1, forKey: item)
      } else {
        valueToCount.updateValue(value: 1, forKey: item)
      }
    }
    return valueToCount;
  }
}

这应该返回出现在数组中的每个不同值的频率。但当然,由于这些值必须是可散列的,因此该扩展仅在应用于 Array&lt;T:Hashable&gt; 时才有效。

但这不适用于Array&lt;Int&gt;,即使 Int 是可散列的。

为什么不呢?如果您在泛型类型上编写扩展,该扩展是否必须能够适用于泛型类型的所有可能特化?

【问题讨论】:

    标签: arrays generics swift


    【解决方案1】:

    您可以扩展SequenceType 而不是Array,这会为您提供更多适用的类型,然后您可以使用where 限制Element 的类型。

    • Array 扩展需要where Element : SomeProtocol
    • SequenceType 扩展需要where Generator.Element : SomeProtocol

    您遇到的问题不是Int 不是Hashable,而是Item 不一定是Hashable。转换为 ItemType 也有效,因为在此示例中它始终为 Hashable

    我个人不会为此使用泛型。由于 Element 已经涵盖了您可以存储在 Array 中的所有内容,因此无需对其进行类型模糊处理。

    extension SequenceType where Generator.Element : Hashable {
    
        func dictionaryCountingFrequencies() -> Dictionary<Generator.Element,Int> {
            var valueToCount = Dictionary<Generator.Element,Int>()
            for item in self {
    
                if let existingCount = valueToCount[item] {
                    valueToCount.updateValue(existingCount + 1, forKey: item)
                } else {
                    valueToCount.updateValue(1, forKey: item)
                }
            }
            return valueToCount;
        }
    }
    
    let array = [1,2,3,4,5,1,1,1,2,3,3]
    
    let freqDict = array.dictionaryCountingFrequencies()
    // prints [5: 1, 2: 2, 3: 3, 1: 4, 4: 1]
    freqDict[5]
    // prints 1
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-02-11
      • 2011-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多