为了好玩,我尝试扩展 Dictionary 类来复制 Python 的 Counter 类。我正在尝试实现 init
,取CollectionType
作为唯一的论点。然而,Swift 不允许这样做,因为 CollectionType
的关联类型。所以,我尝试编写这样的代码:
import Foundation
// Must constrain extension with a protocol, not a class or struct
protocol SingletonIntProtocol { }
extension Int: SingletonIntProtocol { }
extension Dictionary where Value: SingletonIntProtocol { // i.e. Value == Int
init(from sequence: SequenceType where sequence.Generator.Element == Key) {
// Initialize
}
}
但是,Swift 不允许在参数列表中使用这种语法。有没有办法写init
这样它就可以采用任何符合 CollectionType
的类型其值的类型为Key
(泛型 Dictionary<Key: Hashable, Value>
中使用的类型名称)?最好我不会被迫写 init(from sequence: [Key])
,这样我就可以采取任何 CollectionType
(例如 CharacterView
)。
最佳答案
您只是遇到了语法问题。你的基本想法看起来不错。正确的语法是:
init<Seq: SequenceType where Seq.Generator.Element == Key>(from sequence: Seq) {
这个答案的其余部分只是解释了为什么语法是这样的。如果第一部分让您满意,您实际上不需要阅读其余部分。
细微的差别在于,您尝试将 SequenceType where sequence.Generator.Element == Key
视为类型。它不是一种类型;而是一种类型。这是一个类型约束。正确的语法含义是:
There is a type
Seq
such thatSeq.Generator.Element == Key
, andsequence
must be of that type.
虽然这看起来是同一件事,但不同之处在于 Seq
在任何给定时间都是一种特定类型。它不是“任何遵循此规则的类型”。它实际上是一种特定类型。每次您使用某种类型(例如 [Key]
)调用 init
时,Swift 都会创建一个全新的 init
方法,其中 Seq
替换为 [Key]
。 (实际上,Swift 有时可以优化掉这个额外的方法,但原则上它是存在的。)这是理解泛型语法的关键点。
或者你可以只记住尖括号的位置,让编译器在你搞砸的时候提醒你,然后就到此为止了。大多数人在不学习支撑它的类型理论的情况下也能做得很好。
关于swift - 如何约束函数参数的协议(protocol)关联类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36320320/