Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function with generic type

Tags:

generics

swift

I have a function that can calculate the sum of numbers in array with condition like so:

func sumOfArrayWithCondition(array: [Int], filter: (element: Int) -> Bool) -> Int {
    var result = 0
    for i in 0..<array.count where filter(element: array[i]) {
        result += array[i] 
    }
    return result 
}

Now I want it to work with Int, Float, Double type. I have tried, but didn't work.

protocol Addable {
    func +(lhs: Self, rhs: Self) -> Self
}

extension Int: Addable {}
extension Double: Addable {}
extension Float: Addable {}

func sumOfArrayWithCondition<T: Addable>(array: [T], filter: (element: T) -> Bool) -> T {
    var result = 0
    for i in 0..<array.count where filter(element: array[i]) {
        result += array[i] // <-------- Error here
    }
    return result // <-------- Error here
}

But it says:

Binary operator '+=' cannot be applied to operands of type 'Int' and 'T'

So how to do it.

Any helps would be appreciated. Thanks.

like image 789
Khuong Avatar asked Apr 22 '26 07:04

Khuong


1 Answers

First issue is that the compiler is inferring the type Int for the var result because you don't declare a type and initialize it with 0. But you need result to be of type T.

First, in order to initialize result as an instance of type T with the value 0, you need to specify that Addable is also IntegerLiteralConvertible, which is already true for Int, Double and Float. Then you can declare result as type T and go from there.

As Rob pointed out, you also need to add the += function to your protocol if you want to be able to use it.

So the final code that achieves what you are looking for is:

protocol Addable : IntegerLiteralConvertible {
    func +(lhs: Self, rhs: Self) -> Self
    func +=(inout lhs: Self, rhs: Self)
}

extension Int: Addable {}
extension Double: Addable {}
extension Float: Addable {}

func sumOfArrayWithCondition<T: Addable>(array: [T], filter: (element: T) -> Bool) -> T {
    var result:T = 0
    for i in 0..<array.count where filter(element: array[i]) {
        result += array[i]
    }
    return result
}
like image 164
Daniel Hall Avatar answered Apr 24 '26 02:04

Daniel Hall