Comparing objects in an Array extension causing error in Swift

后端 未结 6 518
遥遥无期
遥遥无期 2021-01-22 15:51

I\'m trying to build an extension that adds some of the convenience functionality of NSArray/NSMutableArray to the Swift Array class, and I\'m trying to add this function:

相关标签:
6条回答
  • 2021-01-22 16:17

    You can always create an extension that uses NSArray's indexOfObject, e.g:

    extension Array {
        func indexOfObject(object:AnyObject) -> Int? {
            return (self as NSArray).indexOfObject(object)
        }
    }
    

    You can specify that your array items can be compared with the <T : Equatable> constraint, then you can cast your object into T and compare them, e.g:

    extension Array {
        func indexOfObject<T : Equatable>(o:T) -> Int? {
            if self.count > 0 {
                for (idx, objectToCompare) in enumerate(self) {
                    let to = objectToCompare as T
                    if o == to {
                        return idx
                    }
                }
            }
    
            return nil
        }
    }
    
    0 讨论(0)
  • 2021-01-22 16:17

    You can extract the compare part to another helper function, for example

    extension Array {
        func indexOfObject(object: T, equal: (T, T) -> Bool) -> Int? {
    
            if self.count > 0 {
                for (idx, objectToCompare) in enumerate(self) {
                    if equal(object, objectToCompare) {
                        return idx
                    }
                }
            }
    
            return nil
        }
    }
    
    let arr = [1, 2, 3]
    
    arr.indexOfObject(3, ==) // which returns {Some 2}
    
    0 讨论(0)
  • 2021-01-22 16:20

    Actually there is no need to implement indexOfObject:; there is a global function find(array, element) already.

    0 讨论(0)
  • 2021-01-22 16:21

    You were close. Here's a working extension:

    extension Array {
        func indexOfObject<T: Equatable>(object:T) -> Int? {
            if self.count > 0 {
                for (idx, objectToCompare) in enumerate(self) {
                    if object == objectToCompare as T {
                        return idx
                    }
                }
            }
            return nil
        }
    }
    

    Swift had no way of knowing if object or objectToCompare were equatable. By adding generic information to the method, we're then in business.

    0 讨论(0)
  • 2021-01-22 16:34

    My guess is that you have to do something like this:

    func indexOfObject<T: Equatable>(object: T) -> Int? {
    

    and so on.

    0 讨论(0)
  • 2021-01-22 16:35

    Here's a relevant example from Apple's "The Swift Programming Language" in the "Generics" section:

    func findIndex<T: Equatable>(array: T[], valueToFind: T) -> Int? {
        for (index, value) in enumerate(array) {
            if value == valueToFind {
                return index
            }
        }
        return nil
    }
    

    The key idea here is that both value and valueToFind must of a type that is guaranteed to have the == operator implemented/overloaded. The <T: Equatable> is a generic that allows only objects of a type that are, well, equatable.

    In your case, we would need to ensure that the array itself is composed only of objects that are equatable. The Array is declared as a struct with a generic <T> that does not require it to be equatable, however. I don't know whether it is possible to use extensions to change what kind of types an array can be composed of. I've tried some variations on the syntax and haven't found a way.

    0 讨论(0)
提交回复
热议问题