如何比较"任何"价值类型

时间:2016-01-13 23:19:38

标签: swift

我有几个"任何"我要比较的值类型。

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

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

print(any1 == any2)
print(any2 == any3)
print(any3 == any4)

使用==运算符会显示错误:

  

"二元运算符' =='不适用于两个任何' (又名   '协议<>')操作数"

这样做的方法是什么?

6 个答案:

答案 0 :(得分:22)

执行此操作的唯一方法是使用除==之外的函数来获取类型参数,然后比较这些值是否属于该类型:

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
}

现在,使用上面的变量,你可以像这样比较它们:

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

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

isEqual(Int.self, a: any1, b: any2)      // true
isEqual(Int.self, a: any2, b: any3)      // false
isEqual(String.self, a: any3, b: any4)   // true

答案 1 :(得分:3)

要使用==运算符,键入必须符合Equatable协议。 Any协议不符合Equatable协议,因此无法比较两个Any值。这是合乎逻辑的 - Any是一个过于宽泛的术语 - 价值观没有“共同点”。

更重要的是,Swift不允许比较具有不同类型的两个Equatable值。例如。 IntString都符合Equatable1 == "1"无法编译。原因是在==协议Equatable中声明了func ==(lhs: Self, rhs: Self) -> BoolSelf。这个Self基本上意味着两个参数必须具有相同的类型。它是一种占位符 - 在特定类型的实现中,String user = pref.getString("user", default_user); 应该替换为此类型的名称。

答案 2 :(得分:3)

您可以使用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

由于并非每个Equatable都必须是Hashable,所以在极少数情况下这可能会失败。

通常没有必要使用上述技巧;但有时您会需要它,就像有时需要AnyHashable

答案 3 :(得分:1)

您可以使用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)

这应该产生:- 真正 假 真正 假 是

答案 4 :(得分:1)

亚伦·拉斯穆森(Aaron Rasmussen)的答案也可以用作扩展,例如:

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

答案 5 :(得分:0)

我们可以通过以下方式解决

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