我正在尝试在 Array 中添加一个扩展方法,如下所示:
extension Array {
func contains(obj: T) -> Bool {
let filtered = self.filter {$0 == obj}
return filtered.count > 0
}
}
但self.filter {$0 == obj}
不要工作。编译器错误:
找不到接受提供的参数的“==”的重载
我正在尝试在 Array 中添加一个扩展方法,如下所示:
extension Array {
func contains(obj: T) -> Bool {
let filtered = self.filter {$0 == obj}
return filtered.count > 0
}
}
但self.filter {$0 == obj}
不要工作。编译器错误:
找不到接受提供的参数的“==”的重载
您实际上不需要编写扩展,您可以使用contains
Swift 库中的全局函数:
contains([1,2,3], 1)
正如我在评论中提到的,有一个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 包含SequenceType.contains
,这正是您想要创建的。
这可以通过允许将方法限制为某些(例如 Equatable)类型参数的 Swift 语法来实现。它看起来像这样:
extension SequenceType where Generator.Element: Equatable {
func contains(element: Self.Generator.Element) -> Bool {
...
}
}
我发现内置 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
}
}
这适用于 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
}
}
不完美,但这个基于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
}
请注意,您可能认为您可以直接调用unwrapOptionals
inside func contains<U : Equatable>(obj: U?)
。但是,这不起作用,因为Element
Array 扩展中的类型只是一个类型——它不“知道”它是一个可选类型。因此,如果您调用unwrapOptionals
,将调用第二个版本,并且您将得到充满可选值的数组。