[英]Tuple-type in Swift generic constraint
I'm trying to write a generic function in Swift with the constraint that the parameter must be a sequence of pairs (which I'm going to turn into a dictionary). 我试图在Swift中编写一个泛型函数,其约束条件是该参数必须是成对的序列(我将把它变成字典)。 Is this possible?
这可能吗? I've tried a number of variations on the following, but the compiler doesn't like any of them.
我已经尝试了以下几种变体,但是编译器不喜欢其中任何一种。
func foo<K, V, S: SequenceType where S.Generator.Element == (K,V)>(xs: S) { //...}
Not a direct answer to your question, but if you want to create a dictionary then you could define your function as an extension method to Dictionary
and use the fact that Dictionary
defines 不是您问题的直接答案,但是如果您想创建字典,则可以将函数定义为
Dictionary
的扩展方法,并使用Dictionary
定义的事实
typealias Element = (Key, Value)
Then your method declaration could be 然后你的方法声明可能是
extension Dictionary {
func foo<S : SequenceType where S.Generator.Element == Element>(xs : S) {
//...
}
}
To create a dictionary from the tuples, an init method might be more appropriate, for example 要从元组创建字典,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
}
}
}
Usage: 用法:
let d = Dictionary(xs: [("a", 1), ("b", 2)])
println(d) // [b: 2, a: 1]
Note: The enumation via generate()
and next()
in above code is a workaround for the problem that, for some reason 注意:上面代码中通过
generate()
和next()
进行的枚举是解决由于某种原因而出现的问题的方法
for (key, value) in xs { }
does not compile. 不编译。 Compare Implementing Set.addSequence in Swift .
比较Swift中的实现Set.addSequence 。
Update: As of Swift 2/Xcode 7, the above method can be simplified to 更新:从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
}
}
}
It looks like a compiler bug to me. 在我看来,这似乎是一个编译器错误。
Problem here is that: you cannot use tuple type directly in generic parameters. 这里的问题是:您不能直接在通用参数中使用元组类型。
As @MartinR said in his answer, it works if we use typealias
ed tuple type. 就像@MartinR在他的回答中说的那样,如果我们使用
typealias
ed元组类型,它就可以工作。 But of course, we cannot declare generic typealias
in global context. 但是,当然,我们不能在全局上下文中声明泛型类型
typealias
。
For example, this compiles and works: 例如,它可以编译并运行:
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"])
One more idea is something like this: 另一个想法是这样的:
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"]))
In this case, you must wrap the sequence of tuple with SequenceOfTuple
type, then pass it to foo()
. 在这种情况下,必须使用
SequenceOfTuple
类型包装元组SequenceOfTuple
,然后将其传递给foo()
。
Hmm... 嗯...
You can use a struct with a subscript and store the results in a Dictionary: 您可以将结构体与下标一起使用,并将结果存储在Dictionary中:
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.