jyet jyet - 3 months ago 6
Swift Question

How to pass predicate correctly in the closure in this case?

While passing predicate in the closure in the generic function, I get follwoing errors. How can I solve this.

func find <T: IteratorProtocol> (generator : T, predicate: (T.Element) -> Bool) -> T.Element? {
var gen = generator
while let x = gen.next() {
if predicate(x) {
return x
}
}
return nil
}

var nums:[Int] = [2,3,5,6]


Error: cannot convert value of type '(Int) -> Bool' to expected argument type '(_) -> Bool'

let get = find(generator: nums){ (x:Int) -> Bool in
return x <= 4
}


If I change the closure as follow, the error is
ambiguous use of operator '<='

let get = find(generator: nums) {
$0 <= 4
}


If I cast the value to Int, error: generic parameter 'T' could not be inferred.

let get = find(generator: nums) {
let b = $0 as Int
return b <= 4
}

Answer

Your find function takes an iterator as an argument, not a sequence. An array conforms to Sequence but not to IteratorType. So your predicates are correct, but you have to pass the sequences iterator as the first argument:

let get = find(generator: nums.makeIterator()) { (x:Int) -> Bool in
    return x <= 4
}

or

let get = find(generator: nums.makeIterator())  {
    $0 <= 4
}

or change your function to take a Sequence argument.

But note that you achieve the same result with the existing first(where:) method introduced in Swift 3:

if let y = nums.first(where: { $0 <= 4 } ) {
    print(y)
}
Comments