2

I am trying to write an extension of the Swift Array, but I am getting some wierd errors as I try to compile.

My code:

extension Array
{
    func itemExists<T: Equatable>(item: T) -> Bool
    {
        for elt in self
        {
            if elt == item
            {
                return true
            }
        }
        return false
    }
}

Error:

Cannot invoke '==' with an argument list of type '(T, T)'

Why am I getting this? I am using the Equatable protocol?

What I also tried was:

extension Array
{
    func itemExists<T: Equatable>(item: T) -> Bool
    {
        var array:[T] = self
        for elt in array
        {
            if elt == item
            {
                return true
            }
        }
        return false
    }
}

Where I got a funny error:

'T' is not identical to 'T'

What am I missing? I read the Apple Documentation about it but I am already using the Equatable protocol to be able to use the == operator on 'T'.

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Dejan Skledar
  • 11,280
  • 7
  • 44
  • 70
  • Don't you have to make the items of your Array extension also conform to Equatable: `extension Array `? – Vasil Garov May 19 '15 at 07:56
  • Your method would only be applicable to arrays of Equatable elements, and you cannot write a method on a generic type that is more restrictive on the template. Compare http://stackoverflow.com/questions/24938948/array-extension-to-remove-object-by-value http://stackoverflow.com/questions/24091046/unable-to-use-contains-within-a-swift-array-extension or http://stackoverflow.com/questions/27350941/is-it-possible-to-make-an-array-extension-in-swift-that-is-restricted-to-one-cla. – One of those should qualify as a "duplicate". – Martin R May 19 '15 at 08:04
  • Thank you @MartinR, I found my answer and my mistake there. – Dejan Skledar May 19 '15 at 08:10

2 Answers2

2

With Swift 3.0 (and I think some of the later 2.x versions), you can solve this by referencing the associated type Element with a where clause:

extension Array where Element: Equatable
{
    func itemExists(item: Element) -> Bool
    {
        for elt in self
        {
            if elt == item
            {
                return true
            }
        }
        return false
    }
}
herzi
  • 774
  • 6
  • 18
  • This should be the accepted answer as of Swift 4.2. Thanks for the help - I forgot you can use `Element` as your constrained type in the extension. – Trev14 Feb 27 '19 at 21:58
1

I found my solution.

As MartinR alreary said, my method would only be applicable to arrays of Equatable elements, and you cannot write a method on a generic type that is more restrictive on the template.

There are two ways - writing my code as a function and not as an extension, or use this trick:

extension Array
{
    func itemExists<T: Equatable>(item: T) -> Bool
    {
        return self.filter({$0 as? T == item}).count > 0
    }
}
Dejan Skledar
  • 11,280
  • 7
  • 44
  • 70
  • Are you aware that Swift already has a `contains()` function? See http://stackoverflow.com/questions/24102024/how-to-check-if-an-element-is-in-an-array. – Martin R May 19 '15 at 08:28