Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift Generics issue

Tags:

swift

Right now I want to be able to see if an object is included inside an Array so:

func isIncluded<U:Comparable>(isIncluded : U) -> Bool
{
    for item in self
    {
        if (item == isIncluded)
        {
            return true
        }
    }

    return false
}

If you notice this function belongs to an Array extension. The problem is if add it to this:

extension Array{

}

I receive the following error:

Could not find an overload for '==' that accepts the supplied arguments

enter image description here

I understand that I could probably need to tell what kind of objects should be inside the Array like so: T[] <T.GeneratorType.Element: Comparable>. But it doesn't work as well:

Braced block of statements is an unused closure
Non-nominal type 'T[]' cannot be extended
Expected '{' in extension

enter image description here

like image 792
Rui Peres Avatar asked Jun 04 '14 09:06

Rui Peres


Video Answer


2 Answers

With Swift, we'll need to think whether there's a function that can do the trick -- outside the methods of a class.

Just like in our case here:

contains(theArray, theItem)

You can try it in a playground:

let a = [1, 2, 3, 4, 5]
contains(a, 3)
contains(a, 6)

I discover a lot of these functions by cmd-clicking on a Swift symbol (example: Array) and then by looking around in that file (which seems to be the global file containing all declarations for Swift general classes and functions).

Here's a little extension that will add the "contains" method to all arrays:

extension Array {
    func contains<T: Equatable>(item: T) -> Bool {
        for i in self {
            if item == (i as T) { return true }
        }
        return false
    }
}
like image 131
Jean Le Moignan Avatar answered Sep 27 '22 18:09

Jean Le Moignan


To add, the problem is that T is already defined and the Array's definition of T does not conform to Equatable. You can either accomplish what you want by casting (like the accepted answer), and risking an invalid cast, or you could pass in a delegate where no casting would be required.

Consider modifying like so:

extension Array {
   func contains(comparator: (T)->Bool) -> Bool {
    for item in self {
        if comparator(item) {
           return true
        }
    }
    return false
  }
}

Example usage:

class Test {
    func arrayContains(){
        var test: Int[] = [0,1,3,4,5]
        //should be true 
        var exists = test.contains({(item)->Bool in item == 0});
    }
}
like image 41
wbennett Avatar answered Sep 27 '22 19:09

wbennett