4

我正在尝试在 Array 中添加一个扩展方法,如下所示:

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

self.filter {$0 == obj}不要工作。编译器错误:

找不到接受提供的参数的“==”的重载

4

5 回答 5

32

您实际上不需要编写扩展,您可以使用containsSwift 库中的全局函数:

contains([1,2,3], 1)
于 2014-07-21T13:18:31.460 回答
13

斯威夫特 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(测试版)

Swift 2 包含SequenceType.contains,这正是您想要创建的。

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

extension SequenceType where Generator.Element: Equatable {
    func contains(element: Self.Generator.Element) -> Bool {
        ...
    }
}
于 2014-06-06T21:42:34.450 回答
1

我发现内置 contains 不适用于引用类型。我需要这个并用下面的代码解决了它。我将它粘贴在这里是因为其他人可能会像我一样对 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
    }
} 
于 2015-05-06T21:13:28.833 回答
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
    }
}
于 2015-11-11T20:12:36.450 回答
0

不完美,但这个基于nschum 的答案的版本也支持可选参数(虽然不是具有可选类型的数组):

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!)
    }

}

如果你有一个可选数组,你可以通过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
}

请注意,您可能认为您可以直接调用unwrapOptionalsinside func contains<U : Equatable>(obj: U?)。但是,这不起作用,因为ElementArray 扩展中的类型只是一个类型——它不“知道”它是一个可选类型。因此,如果您调用unwrapOptionals,将调用第二个版本,并且您将得到充满可选值的数组。

于 2015-02-07T05:33:38.993 回答