How to compare “Any” value types

前端 未结 6 521
我在风中等你
我在风中等你 2020-12-15 05:03

I have several \"Any\" value types that I want to compare.

var any1: Any = 1
var any2: Any = 1

var any3: Any = \"test\"
var any4: Any = \"test\"

print(any1         


        
相关标签:
6条回答
  • 2020-12-15 05:25

    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.

    0 讨论(0)
  • 2020-12-15 05:30

    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
    
    0 讨论(0)
  • 2020-12-15 05:30

    We can solve it in the following way

    enum SwiftDataType
    {
        case String
        case Int
        case Int64
        case Double
        case Bool
        case Undefined
    }
    
    func getType( of : Any ) -> SwiftDataType
    {
        if let type = of as? String
        {
            return SwiftDataType.String
        }
        else if let type = of as? Int
        {
            return SwiftDataType.Int
        }
        else if let type = of as? Int64
        {
            return SwiftDataType.Int64
        }
        else if let type = of as? Double
        {
            return SwiftDataType.Double
        }
        else if let type = of as? Bool
        {
            return SwiftDataType.Bool
        }
        else
        {
            return SwiftDataType.Undefined
        }
    }
    
    func isEqual( a : Any, b : Any ) -> Bool
    {
        let aType : SwiftDataType = getType( of : a )
        let bType : SwiftDataType = getType( of : b )
        if aType != bType
        {
            print("Type is not Equal -> \(aType)")
            return false
        }
        else
        {
            switch aType  {
            case SwiftDataType.String :
                guard let aValue = a as? String, let bValue = b as? String else
                {
                    return false
                }
                return aValue == bValue
    
            case SwiftDataType.Int :
                guard let aValue = a as? Int, let bValue = b as? Int else
                {
                    return false
                }
                return aValue == bValue
    
            case SwiftDataType.Int64 :
                guard let aValue = a as? Int64, let bValue = b as? Int64 else
                {
                    return false
                }
                return aValue == bValue
    
            case SwiftDataType.Double :
                guard let aValue = a as? Double, let bValue = b as? Double else
                {
                    return false
                }
                return aValue == bValue
    
            case SwiftDataType.Bool :
                guard let aValue = a as?  Bool, let bValue = b as? Bool else
                {
                    return false
                }
                return aValue == bValue
    
            default:
                return false
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-15 05:32

    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) )
      }
    }
    
    0 讨论(0)
  • 2020-12-15 05:43

    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.

    0 讨论(0)
  • 2020-12-15 05:43

    You can use NSObject ...

    var any1: Any = 1
    var any2: Any = 1
    
    var any3: Any = "test"
    var any4: Any = "test"
    
    var any5: Any? = nil
    var any6: Any? = nil
    
    print(any1 as? NSObject == any2 as? NSObject)
    print(any2 as? NSObject == any3 as? NSObject)
    print(any3 as? NSObject == any4 as? NSObject)
    print(any4 as? NSObject == any5 as? NSObject)
    print(any5 as? NSObject == any6 as? NSObject)
    

    This should produce :- true false true false true

    0 讨论(0)
提交回复
热议问题