最优雅的方式来比较Swift中的两个选项

时间:2016-03-17 16:43:30

标签: swift optional

我有两个AnyObject?变量,我想比较参考相等:

var oldValue: AnyObject?
var newValue: AnyObject?
...
if oldValue != newValue {
    changed = true
}

但这并不起作用,因为我显然无法直接比较两个选项。我希望这种行为好像我在Objective-C中比较id,即:

  • true如果两者都是nil
  • true如果两者都有值且值也相等
  • false否则

有没有一种优雅的方式在Swift中编写它(理想情况下无需编写自定义扩展)?

这是我提出的最佳选择:

if !(oldValue != nil && newValue != nil && oldValue == newValue)

不太漂亮。 :(

5 个答案:

答案 0 :(得分:11)

假设您正在使用可比实体,这将适用于任何事情:

func optionalsAreEqual<T: Comparable>(firstVal: T?, secondVal: T?) -> Bool{

    if let firstVal = firstVal, secondVal = secondVal {
        return firstVal == secondVal
    }
    else{
        return firstVal == nil && secondVal == nil
   }
}

它不是短暂而甜蜜的,但它具有表现力,清晰和​​可重复使用。

答案 1 :(得分:11)

您可以使用!==

来自 Swift编程语言

  

Swift还提供了两个身份运算符(===!==),您可以使用它们测试两个对象引用是否同时引用同一个对象实例。

一些很好的例子和解释也在Difference between == and ===

在@PEEJWEEJ点上,执行以下操作将导致false

var newValue: AnyObject? = "String"
var oldValue: AnyObject? = "String"

if newValue === oldValue {
   print("true")
} else {
   print("false")
}

答案 2 :(得分:4)

我喜欢@Keith's解决方案。但我认为它不是用Swift 4编写的,因为我无法用Swift 4编译器编译它。

所以我在这里将他的代码转换为Swift 4版本。

请注意,如果您使用的是Swift语言的版本高于 Swift 4.1 ,则此答案无需,因为它默认提供此功能。您可以参考here了解更多详情。

@ Keith代码的Swift 4版本:

infix operator ==? : ComparisonPrecedence

func ==? <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
    if let lhs = lhs, let rhs = rhs {
        return lhs == rhs
    } else {
        return lhs == nil && rhs == nil
    }
}

func ==? <T: AnyObject>(lhs: T?, rhs: T?) -> Bool {
    if let lhs = lhs, let rhs = rhs {
        return lhs === rhs
    } else {
        return lhs == nil && rhs == nil
    }
}

答案 3 :(得分:3)

我定义了一个自定义中缀运算符,它具有引用类型和值类型的函数。

func ==? <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
    if let lhs = lhs, rhs = rhs {
        return lhs == rhs
    } else{ return lhs == nil && rhs == nil }
}
func ==? <T: AnyObject>(lhs: T?, rhs: T?) -> Bool {
    if let lhs = lhs, rhs = rhs {
        return lhs === rhs
    } else{ return lhs == nil && rhs == nil }
}
infix operator ==? { associativity left precedence 130 }

var aString: String? = nil
var bString: String? = nil
print(aString ==? bString) // true

aString = "test"
bString = "test"
print(aString ==? bString) // true

aString = "test2"
bString = "test"
print(aString ==? bString) // false

aString = "test"
bString = nil
print(aString ==? bString) // false

class TT {}
let x = TT()

var aClass: TT? = TT()
var bClass: TT? = TT()
print(aClass ==? bClass) // false

aClass = TT()
bClass = nil
print(aClass ==? bClass) // false

aClass = nil
bClass = nil
print(aClass ==? bClass) // true

aClass = x
bClass = x
print(aClass ==? bClass) // true

答案 4 :(得分:0)

对于某些==类型,您可以重载Comparable运算符

public func ==<T: SomeType>(lhs: T?, rhs: T?) -> Bool {
    switch (lhs,rhs) {
    case (.some(let lhs), .some(let rhs)):
        return lhs == rhs
    case (.none, .none):
        return true
    default:
        return false
    }
}

或者将===用于AnyObject的比较,但就我个人而言,我不希望一开始就使用AnyObject