如何约束函数参数的协议相关类型

时间:2016-03-30 21:46:13

标签: swift swift-extensions

为了好玩,我试图扩展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)。

1 个答案:

答案 0 :(得分:3)

您只是遇到语法问题。你的基本想法似乎很好。正确的语法是:

init<Seq: SequenceType where Seq.Generator.Element == Key>(from sequence: Seq) {

这个答案的其余部分只是解释了为什么语法是这样的。如果第一部分满足你的要求,你真的不需要阅读其余部分。

微妙的区别在于您试图将SequenceType where sequence.Generator.Element == Key视为一种类型。它不是一种类型;这是一种类型约束。正确的语法意味着:

  

Seq类型,Seq.Generator.Element == Keysequence必须属于该类型。

虽然这似乎是相同的,但区别在于Seq在任何给定时间都是一种特定类型。它不是“遵循这条规则的任何类型”。它实际上是一种特定的类型。每当您使用某种类型(init)致电[Key]时,Swift都会创建一个全新的init方法,其中Seq将替换为[Key]。 (实际上,Swift有时可以优化额外的方法,但原则上它存在。)这是理解通用语法的关键点。

或者你可以只记住尖括号的位置,让编译器在你把它搞砸时提醒你,然后调用它。大多数人在没有学习支撑它的类型理论的情况下做得很好。