【问题标题】:Most elegant way to compare two optionals in Swift在 Swift 中比较两个选项的最优雅的方法
【发布时间】:2016-03-17 16:43:29
【问题描述】:

我有两个 AnyObject? 变量,我想比较它们的引用相等性:

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

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

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

有没有一种优雅的方式在 Swift 中编写(最好不需要编写自定义扩展)?

这是我想出的最好的:

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

不是很漂亮。 :(

【问题讨论】:

  • 真的是这样吗?!我总是忘记那个操作员!
  • @sbarow 我想你真的明白了。如果您需要代表,请发布答案。
  • 参考比较是我想要的。我没有发布变量获取值的代码。
  • 由于 Javascript 及其与 ===== 的时髦行为,我无法忘记该运算符;-)

标签: swift optional


【解决方案1】:

假设您使用的是 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
   }
}

它并不短小精悍,但它富有表现力、清晰且可重复使用。

【讨论】:

  • 虽然这不是我想要的,但感谢您发布此内容,以防其他人正在寻找非参考比较。
【解决方案2】:

你可以使用!==

来自 Swift 编程语言

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

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

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

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

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

【讨论】:

  • 仅供参考,我认为如果 oldValue 和 newValue 是对象, === 将始终为 false,除非它们实际上设置为同一个对象。
【解决方案3】:

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

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

请记住,如果您使用的是比 Swift 4.1 更高版本的 Swift 语言,那么 不需要此答案,因为它默认提供此功能。您可以参考here 了解更多详情。

Swift 4 版本的@Keith 的代码:

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

【讨论】:

    【解决方案4】:

    我为引用类型和值类型定义了一个自定义中缀运算符。

    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
    

    【讨论】:

    • Equatable 还不够吗?
    • 我假设这是用 Swift 3 编写的。我是正确的@Keith?
    【解决方案5】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-16
      • 1970-01-01
      • 2010-09-22
      • 2017-08-17
      相关资源
      最近更新 更多