How to compare "Any" value types
The only way to do this is with a function other than ==
that takes a type parameter, and then compares the values if they are both of that type:
func isEqual<T: Equatable>(type: T.Type, a: Any, b: Any) -> Bool {
guard let a = a as? T, let b = b as? T else { return false }
return a == b
}
Now, using your variables above, you can compare them like this:
var any1: Any = 1
var any2: Any = 1
var any3: Any = "test"
var any4: Any = "test"
isEqual(type: Int.self, a: any1, b: any2) // true
isEqual(type: Int.self, a: any2, b: any3) // false
isEqual(type: String.self, a: any3, b: any4) // true
To use ==
operator, type has to conform to Equatable
protocol. Any
protocol does not conform to Equatable
protocol, so there is no way to compare two Any
values. It's logical - Any
is too broad term - values can have no 'common denominator'.
What's more, Swift doesn't allow to compare two Equatable
values which have different type. E.g. both Int
and String
conform to Equatable
but 1 == "1"
does not compile. The reason for that is the declaration of ==
in Equatable
protocol: func ==(lhs: Self, rhs: Self) -> Bool
. This Self basically means that both arguments have to have the same type. It it's kind of a placeholder - in implementation for specific type, Self
should be replaced with the name of this type.
You can do it like this by using AnyHashable
:
func equals(_ x : Any, _ y : Any) -> Bool {
guard x is AnyHashable else { return false }
guard y is AnyHashable else { return false }
return (x as! AnyHashable) == (y as! AnyHashable)
}
print("\(equals(3, 4))") // false
print("\(equals(3, equals))") // false
print("\(equals(3, 3))") // true
As not every Equatable
has to be Hashable
, this might fail under rare circumstances.
Usually there is no reason for using above hack; but sometimes you will need it, just as sometimes AnyHashable
is needed.
Aaron Rasmussen's answer can also be used as an extension, like so:
public extension Equatable {
/// Equate two values of unknown type.
static func equate(_ any0: Any, _ any1: Any) -> Bool {
guard
let equatable0 = any0 as? Self,
let equatable1 = any1 as? Self
else { return false }
return equatable0 == equatable1
}
}
final class EquatableTestCase: XCTestCase {
func test_equate() {
let int: Any = Int.random( in: .min...(.max) )
let bool: Any = Bool.random()
XCTAssertTrue( Int.equate(int, int) )
XCTAssertTrue( .equate(bool, bool) )
XCTAssertFalse( .equate(int, int) )
XCTAssertTrue( AnyHashable.equate(bool, bool) )
XCTAssertFalse( AnyHashable.equate(bool, int) )
}
}