问题
Can anybody see light on this bug? The playground insists that argument #2 is missing, but there is no argument #1!
The intention of the code to to count the number of runs of a equatable value, and return a sequence of tuples consisting of the values and their counts. I've worked on this code extensively, optimising it and refining it until I'm pretty sure that it should work… but although it compiles, I cannot call it the way it was intended.
The error i get from calling the code below is missing argument for parameter #2 in call
extension SequenceOf {
func CountRuns<T: Equatable>() -> SequenceOf<(T, Int)> {
return SequenceOf<(T, Int)>([])
return SequenceOf<(T, Int)> { () -> GeneratorOf<(T, Int)> in
var generator = self.generate()
var previousValue: T?
var start = true
return GeneratorOf<(T, Int)> { () -> (T, Int)? in
var count = 1
var retValue: (T, Int)?
while(true) {
var value = generator.next() as T?
if start {
previousValue = value
start = false
} else if value != nil && value! == previousValue! {
count++
} else {
if previousValue != nil {
retValue = (previousValue!, count)
}
previousValue = value
break
}
}
return retValue
}
}
}
}
println(SequenceOf(y).CountRuns())
Playground execution failed: <EXPR>:327:23: error: missing argument for parameter #2 in call
println(SequenceOf(y).CountRuns())
^
回答1:
The problem you're having is that you can't actually extend a generic type with a method that further specializes its generic subtype. That is to say, your countRuns
method requires that SequenceOf
's generic subtype T
be Equatable
, but you can only provide those constraints in the original type declaration, not in an extension.
The solution is to declare countRuns
as a top-level function, like so:
func countRuns<T: Equatable>(s: SequenceOf<T>) -> SequenceOf<(T, Int)> {
return SequenceOf<(T, Int)> { () -> GeneratorOf<(T, Int)> in
// note the change from self.generate() to s.generate() here
var generator = s.generate()
var previousValue: T?
var start = true
return GeneratorOf<(T, Int)> { () -> (T, Int)? in
var count = 1
var retValue: (T, Int)?
while(true) {
var value = generator.next() as T?
if start {
previousValue = value
start = false
} else if value != nil && value! == previousValue! {
count++
} else {
if previousValue != nil {
retValue = (previousValue!, count)
}
previousValue = value
break
}
}
return retValue
}
}
}
println(countRuns(SequenceOf(y)))
This was covered (a little) at the end of this NSHipster article.
回答2:
I found a better answer! Thanks Nate for putting me on the right track.
The trick is that the comparator needs to come from the top level, where the type is defined. So, the final solution has only three changes, on the second line, the sixteenth line, and in the call. The change is to pass the comparator, and use the comparator instead of directly compring the values.
extension SequenceOf {
func CountRuns(areEqual: (T, T) -> Bool) -> SequenceOf<(T, Int)> {
return SequenceOf<(T, Int)>([])
return SequenceOf<(T, Int)> { () -> GeneratorOf<(T, Int)> in
var generator = self.generate()
var previousValue: T?
var start = true
return GeneratorOf<(T, Int)> { () -> (T, Int)? in
var count = 1
var retValue: (T, Int)?
while(true) {
var value = generator.next() as T?
if start {
previousValue = value
start = false
} else if value != nil && areEqual(value!, previousValue!) {
count++
} else {
if previousValue != nil {
retValue = (previousValue!, count)
}
previousValue = value
break
}
}
return retValue
}
}
}
}
let y = [0, 0, 0, 2, 2, 2, 3, 4 ,4, 5, 65, 65]
println(SequenceOf(y).CountRuns(==).ToArray())
let z = [0.0, 0.0, 0.0, 2.0, 2.0, 2.0, 3.0, 4.0, 4.0, 5.0, 65.0, 65.0]
println(SequenceOf(z).CountRuns(==).ToArray())
// Prints:
// [(0, 3), (2, 3), (3, 1), (4, 2), (5, 1), (65, 2)]
// [(0.0, 3), (2.0, 3), (3.0, 1), (4.0, 2), (5.0, 1), (65.0, 2)]
This then works as a general solution to the Generic Equatable protocol problem.
来源:https://stackoverflow.com/questions/26156180/swift-missing-argument-in-call-to-argumentless-extension-of-sequenceof