为了好玩,我试图扩展Dictionary类来复制Python的Counter类。我正在尝试实现Call
,以init
为唯一参数。但是,由于CollectionType
的关联类型,Swift不允许这样做。所以,我正在尝试编写这样的代码:
CollectionType
但是,Swift不允许在参数列表中使用此语法。有没有办法编写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
}
}
,以便它可以采用符合init
的任何类型,其值为CollectionType
类型(通用Key
中使用的类型的名称)?最好不要强迫我写Dictionary<Key: Hashable, Value>
,这样我就可以接受任何init(from sequence: [Key])
(比如说CollectionType
)。
答案 0 :(得分:3)
您只是遇到语法问题。你的基本想法似乎很好。正确的语法是:
init<Seq: SequenceType where Seq.Generator.Element == Key>(from sequence: Seq) {
这个答案的其余部分只是解释了为什么语法是这样的。如果第一部分满足你的要求,你真的不需要阅读其余部分。
微妙的区别在于您试图将SequenceType where sequence.Generator.Element == Key
视为一种类型。它不是一种类型;这是一种类型约束。正确的语法意味着:
有
Seq
类型,Seq.Generator.Element == Key
和sequence
必须属于该类型。
虽然这似乎是相同的,但区别在于Seq
在任何给定时间都是一种特定类型。它不是“遵循这条规则的任何类型”。它实际上是一种特定的类型。每当您使用某种类型(init
)致电[Key]
时,Swift都会创建一个全新的init
方法,其中Seq
将替换为[Key]
。 (实际上,Swift有时可以优化额外的方法,但原则上它存在。)这是理解通用语法的关键点。
或者你可以只记住尖括号的位置,让编译器在你把它搞砸时提醒你,然后调用它。大多数人在没有学习支撑它的类型理论的情况下做得很好。