Swift包含Array的扩展

时间:2014-06-06 21:13:18

标签: ios swift class-extensions

我试图在数组中添加扩展方法,如下所示:

extension Array {
    func contains(obj: T) -> Bool {
        let filtered = self.filter {$0 == obj}
        return filtered.count > 0
    }
}

但是self.filter {$0 == obj}不起作用。编译器错误:

  

无法找到' =='接受提供的参数

5 个答案:

答案 0 :(得分:32)

您实际上并不需要编写扩展程序,您可以使用Swift库中的全局函数contains

contains([1,2,3], 1)

答案 1 :(得分:13)

Swift 1.x

正如我在评论中提到的,有一个contains功能。但是要回答如何编写扩展以及编译器错误意味着什么的问题:

数组中的元素无法与==进行比较。您需要确保参数为Equatable,并且需要确保数组元素的类型相同。

extension Array {
    func contains<T : Equatable>(obj: T) -> Bool {
        let filtered = self.filter {$0 as? T == obj}
        return filtered.count > 0
    }
}

Swift 2 / Xcode 7(Beta)

Swift 2包含SequenceType.contains,这正是您尝试创建的内容。

这可以通过Swift语法实现,该语法允许将方法限制为某些(例如Equatable)类型参数。它看起来像这样:

extension SequenceType where Generator.Element: Equatable {
    func contains(element: Self.Generator.Element) -> Bool {
        ...
    }
}

答案 2 :(得分:1)

我发现内置包含不适用于引用类型。我需要这个并使用下面的代码解决它。我在这里粘贴它是因为其他人可能会像我一样对contains()感到困惑。

extension Array {
    func containsReference(obj: AnyObject) -> Bool {
        for ownedItem in self {
            if let ownedObject: AnyObject = ownedItem as? AnyObject {
                if (ownedObject === obj) {
                    return true
                }
            }
        }

        return false
    }
} 

答案 3 :(得分:1)

这适用于Swift 2.1的参考类型非常好。

extension SequenceType where Generator.Element: AnyObject {
    func contains(obj: Self.Generator.Element?) -> Bool {
        if obj != nil {
            for item in self {
                if item === obj {
                    return true
                }
            }
        }
        return false
    }
}

对于值类型,您可以添加:

extension SequenceType where Generator.Element: Equatable {
    func contains(val: Self.Generator.Element?) -> Bool {
        if val != nil {
            for item in self {
                if item == val {
                    return true
                }
            }
        }
        return false
    }
}

答案 4 :(得分:0)

不完美,但是基于nschum's answer构建的这个版本也支持可选参数(尽管不是带有可选类型的数组):

extension Array {

    private func typeIsOptional() -> Bool {
        return reflect(self[0]).disposition == .Optional
    }

    func contains<U : Equatable>(obj: U) -> Bool {
        if isEmpty {
            return false
        }

        if (typeIsOptional()) {
            NSException(name:"Not supported", reason: "Optional Array types not supported", userInfo: nil).raise()
        }

        // cast type of array to type of argument to make it equatable
        for item in self.map({ $0 as? U }) {
            if item == obj {
                return true
            }
        }

        return false
    }

    // without this version, contains("foo" as String?) won't compile
    func contains<U : Equatable>(obj: U?) -> Bool {
        if isEmpty {
            return false
        }

        if (typeIsOptional()) {
            NSException(name:"Not supported", reason: "Optional Array types not supported", userInfo: nil).raise()
        }

        return obj != nil && contains(obj!)
    }

}

如果您有一个选项数组,您可以使用此全局函数thanks to jtbandes获取非选项(删除了nil个参数)的副本:

func unwrapOptionals<T>(a: [T?]) -> [T] {
    return a.filter { $0 != nil }.map { $0! }
}

用法:

 1>     func unwrapOptionals<T>(a: [T?]) -> [T] {
  2.         return a.filter { $0 != nil }.map { $0! }
  3.     }
  4>
  5> let foo = ["foo" as String?]
foo: [String?] = 1 value {
  [0] = "foo"
}
  6> let bar = unwrapOptionals(foo)
bar: [String] = 1 value {
  [0] = "foo"
}

为了更好地衡量,如果类型不是可选的,请添加一个只返回数组的数组。这样,如果在非可选数组上调用unwrapOptionals(),则可以避免运行时错误:

func unwrapOptionals<T>(a: [T]) -> [T] {
    return a
}

请注意,您可能认为可以在unwrapOptionals内拨打func contains<U : Equatable>(obj: U?)。但是,这不起作用,因为Array扩展中的Element类型只是一种类型 - 它不“知道”它是一个可选类型。所以如果你打电话给unwrapOptionals,第二个版本就会被调用,你只需要把阵列装回选项。