问题
I'm trying to test if an array of type [Any] contains a value of a specific type (say, Int).
I'm aware that Swift does not know how to compare an Int and a value of arbitrary type, and I guess that's what's being expressed in the autocomplete template:
contains(predicate: (protocol<>) throws -> Bool)
So I tried this code:
let intValue:Int = 5 // for example
let isContained = myArrayOfAny.contains({ element in
return ((element as? Int) == intValue)
})
...and it compiles (can't make sure it works yet); but still can't make heads or tails of the predicate: (protocol<>) part. What does it mean? The documentation for SequenceType is quite cryptic:
contains(_: (Self.Generator.Element) throws -> Bool) rethrows -> Bool
Default Implementation
Return true iff an element in self satisfies predicate.
Declaration
@warn_unused_result func contains(@noescape _ predicate: (Self.Generator.Element) throws -> Bool) rethrows -> Bool
EDIT: I'm quite confused because, all search results I've seen have the contains() method of Array as just taking the value to be tested for containment, e.g.:
if myArrayOfInt.contains(someInt){
...
and not a closure.
回答1:
There are two different contains() methods (both protocol
extensions to SequenceType). The first one is
extension SequenceType where Generator.Element : Equatable {
/// Return `true` iff `element` is in `self`.
@warn_unused_result
public func contains(element: Self.Generator.Element) -> Bool
}
and it requires that the sequence elements conform to the Equatable
protocol, which guarantees that they can be compared with ==:
public protocol Equatable {
// ...
public func ==(lhs: Self, rhs: Self) -> Bool
}
For example, in
let intValue:Int = 5
let myArrayOfInt = [4, 5, 6]
let isContained = myArrayOfInt.contains(intValue)
you have an array of Int, and Int conforms to Equatable,
so this contains() method can be used to check for the presence
of a certain element.
This does not work for
let myArrayOfAny : [Any] = [4, 5, 6]
because Any does not conform to Equatable. Here you can use
the second contains() method
extension SequenceType {
/// Return `true` iff an element in `self` satisfies `predicate`.
@warn_unused_result
public func contains(@noescape predicate: (Self.Generator.Element) throws -> Bool) rethrows -> Bool
}
which takes a predicate, i.e. a boolean function. Instead of
comparing with ==, the predicate is applied to each array element.
This method does not require that the array elements are Equatable.
And that's what you do in
let myArrayOfAny : [Any] = [4, 5, 6]
let intValue:Int = 5 // for example
let isContained = myArrayOfAny.contains({ element in
return ((element as? Int) == intValue)
})
This will yield true if any array element can be cast to an Int
and is equal to the given intValue.
The might see the first method more frequently but the second is far more general, e.g.
if myArrayOfCustomObjects.contains ({ $0.someProperty == "foo" })
or
if myArrayOfInts.contains ({ $0 > 17 })
So the first contains() is a kind of specialization of the second one for a simple containment check in arrays of equatable elements. It could be implemented as
extension SequenceType where Generator.Element : Equatable {
public func contains(element: Self.Generator.Element) -> Bool {
return self.contains({ $0 == element } )
}
}
You'll find the same with indexOf() which also comes in
two flavors:
extension CollectionType where Generator.Element : Equatable {
// ...
public func indexOf(element: Self.Generator.Element) -> Self.Index?
}
extension CollectionType {
// ...
public func indexOf(@noescape predicate: (Self.Generator.Element) throws -> Bool) rethrows -> Self.Index?
}
来源:https://stackoverflow.com/questions/34081580/array-of-any-and-contains