比较Swift中两个可选语句的最优雅方式

yks3o0rb  于 2023-05-28  发布在  Swift
关注(0)|答案(6)|浏览(133)

我有两个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)

不是很漂亮。:(

mzillmmw

mzillmmw1#

假设你正在使用Comparable实体,这将适用于任何东西:

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

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

它并不完全简短和甜蜜,但它富有表现力,清晰,可重用。

izj3ouym

izj3ouym2#

您可以使用!==
Swift编程语言(Swift Programming Language)
Swift还提供了两个恒等运算符(===!==),用于测试两个对象引用是否都引用同一个对象示例。
Difference between == and ===上也有一些很好的示例和解释
在@PEEJWEEJ点,执行以下操作将得到false

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

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

wz8daaqr3#

我喜欢@基思的解决方案。但我认为它不是用Swift 4写的,因为我不能用Swift 4编译器编译它。
所以我把他的代码转换成Swift 4版本。
请记住,如果您使用的是比Swift 4.1更高版本的Swift语言,那么这个答案是没有必要的,因为它默认提供此功能。您可以参考here了解更多详细信息。

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

ohfgkhjo4#

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

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
rxztt3cl

rxztt3cl5#

可以为某些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

wko9yo5t

wko9yo5t6#

我相信这是基思的旧解决方案的Swift 5版本然而这是泛型。例如,如果您正在比较的对象是String?,它将认为String? = nilString? = ""不相同,尽管两者在语义级别上都是“空”的

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 }
}
infix operator ==?: ComparisonPrecedence

相关问题