【发布时间】:2015-02-12 10:02:52
【问题描述】:
我正在尝试在 Swift 中编写一个通用函数,其约束条件是参数必须是成对的序列(我将把它变成字典)。这可能吗?我尝试了以下几种变体,但编译器不喜欢其中任何一种。
func foo<K, V, S: SequenceType where S.Generator.Element == (K,V)>(xs: S) { //...}
【问题讨论】:
我正在尝试在 Swift 中编写一个通用函数,其约束条件是参数必须是成对的序列(我将把它变成字典)。这可能吗?我尝试了以下几种变体,但编译器不喜欢其中任何一种。
func foo<K, V, S: SequenceType where S.Generator.Element == (K,V)>(xs: S) { //...}
【问题讨论】:
不是直接回答您的问题,但如果您想创建
字典,然后您可以将您的功能定义为扩展
方法到Dictionary 并使用Dictionary 定义的事实
typealias Element = (Key, Value)
那么你的方法声明可以是
extension Dictionary {
func foo<S : SequenceType where S.Generator.Element == Element>(xs : S) {
//...
}
}
要从元组创建字典,init 方法可能更合适,例如
extension Dictionary {
init<S : SequenceType where S.Generator.Element == Element>(xs : S) {
self.init()
var gen = xs.generate()
while let (key, value) : Element = gen.next() {
self[key] = value
}
}
}
用法:
let d = Dictionary(xs: [("a", 1), ("b", 2)])
println(d) // [b: 2, a: 1]
注意: 上面代码中通过generate() 和next() 的枚举
是一种解决方法,由于某种原因
for (key, value) in xs { }
不编译。比较Implementing Set.addSequence in Swift。
更新:从Swift 2/Xcode 7开始,上述方法可以简化 到
extension Dictionary {
init<S : SequenceType where S.Generator.Element == Element>(xs : S) {
self.init()
xs.forEach { (key, value) in
self[key] = value
}
}
}
【讨论】:
对我来说,这看起来像是一个编译器错误。
这里的问题是:不能在泛型参数中直接使用元组类型。
正如@MartinR 在他的回答中所说,如果我们使用typealiased 元组类型,它就可以工作。但当然,我们不能在全局上下文中声明泛型 typealias。
例如,这个编译和工作:
struct Foo<K,V> {
typealias Element = (K,V)
static func foo<S:SequenceType where S.Generator.Element == Element>(xs:S) {
var gen = xs.generate()
while let (k,v): Element = gen.next() {
println((k,v))
}
}
}
Foo.foo(["test":"foo", "bar": "baz"])
还有一个想法是这样的:
struct SequenceOfTuple<K,V>: SequenceType {
typealias Element = (K,V)
let _generate:() -> GeneratorOf<Element>
init<S:SequenceType where S.Generator.Element == Element>(_ seq:S) {
_generate = { GeneratorOf(seq.generate()) }
}
func generate() -> GeneratorOf<Element> {
return _generate()
}
}
func foo<K,V>(xs:SequenceOfTuple<K,V>) {
for (k, v) in xs {
println((k,v))
}
}
foo(SequenceOfTuple(["test":"foo", "bar": "baz"]))
在这种情况下,您必须将元组序列包装成SequenceOfTuple类型,然后将其传递给foo()。
嗯……
【讨论】:
您可以使用带有下标的结构并将结果存储在字典中:
struct Matrix<K:Hashable, V> {
var container:[K:[K:V]] = [:]
subscript(x:K, y:K) -> V? {
get {
return container[x]?[y]
}
set (value) {
if container[x] == nil {
container[x] = [:]
}
container[x]![y] = value
}
}
}
var matrix = Matrix<Int, String>()
matrix[11,42] = "Hello World"
println("(11,42): \(matrix[11,42])") // Optional("Hello World")
println("(1,3): \(matrix[1,3])") // nil
【讨论】: