如何约束函数参数的协议关联类型
How to constrain function parameter's protocol's associated types
为了好玩,我正在尝试扩展词典 class 以复制 Python 的计数器 class。我正在尝试实施 init
,将 CollectionType
作为唯一参数。但是,由于 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
}
}
但是,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 that Seq.Generator.Element == Key
, and sequence
must be of that type.
虽然这看起来是一回事,但不同之处在于 Seq
在任何给定时间都是一种特定类型。它不是 "any type that follows this rule." 它实际上是一种特定类型。每次你用某种类型(比如 [Key]
)调用 init
时,Swift 将创建一个全新的 init
方法,其中 Seq
被替换为 [Key]
. (事实上 ,Swift有时可以优化那个额外的方法,但原则上它存在。)这是理解通用语法的关键点。
或者你可以只记住尖括号的位置,让编译器在你搞砸的时候提醒你,然后就到此为止吧。大多数人在不学习支撑它的类型理论的情况下都做得很好。
为了好玩,我正在尝试扩展词典 class 以复制 Python 的计数器 class。我正在尝试实施 init
,将 CollectionType
作为唯一参数。但是,由于 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
}
}
但是,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
在任何给定时间都是一种特定类型。它不是 "any type that follows this rule." 它实际上是一种特定类型。每次你用某种类型(比如 [Key]
)调用 init
时,Swift 将创建一个全新的 init
方法,其中 Seq
被替换为 [Key]
. (事实上 ,Swift有时可以优化那个额外的方法,但原则上它存在。)这是理解通用语法的关键点。
或者你可以只记住尖括号的位置,让编译器在你搞砸的时候提醒你,然后就到此为止吧。大多数人在不学习支撑它的类型理论的情况下都做得很好。