我试图在Swift中编写一个泛型函数,其约束条件是参数必须是一对对的序列(我将变成一个字典)。这可能吗?我已经尝试了以下几种变体,但编译器并不喜欢它们中的任何一种。
func foo<K, V, S: SequenceType where S.Generator.Element == (K,V)>(xs: S) { //...}
答案 0 :(得分:6)
不是您问题的直接答案,但如果您想创建
然后你可以将你的函数定义为扩展名
方法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
}
}
}
答案 1 :(得分:0)
对我来说,它看起来像编译器错误。
问题在于:您不能在通用参数中直接使用元组类型 。
正如@MartinR在他的回答中所说,如果我们使用typealias
ed元组类型,它就有效。但是,当然,我们不能在全局上下文中声明泛型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()
。
嗯...
答案 2 :(得分:0)
您可以使用带有下标的结构并将结果存储在字典中:
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