Самый элегантный способ сравнить два варианта в Swift
У меня есть две переменные AnyObject?
, которые я хотел бы сравнить для ссылочного равенства:
var oldValue: AnyObject?
var newValue: AnyObject?
...
if oldValue != newValue {
changed = true
}
Это не работает, потому что я, по-видимому, не могу сравнивать сразу два варианта. Мне нужно поведение, как если бы я сравнивал id
в Objective-C, то есть:
-
true
, если оба параметра nil
-
true
, если оба имеют значение, а значения также равны
-
false
иначе
Есть ли элегантный способ записать это в Swift (в идеале без написания пользовательского расширения)?
Это лучшее, что я придумал:
if !(oldValue != nil && newValue != nil && oldValue == newValue)
Не очень красиво.: (
Ответы
Ответ 1
Вы можете использовать !==
От Язык быстрого языка
Swift также предоставляет два идентификационных оператора (===
и !==
), которые вы используете для проверки ссылок на два объекта, которые ссылаются на один и тот же экземпляр объекта.
Некоторые хорошие примеры и объяснения также находятся в Разница между == и ===
В точке @PEEJWEEJ выполнение следующего результата приведет к false
var newValue: AnyObject? = "String"
var oldValue: AnyObject? = "String"
if newValue === oldValue {
print("true")
} else {
print("false")
}
Ответ 2
Предполагая, что вы используете объекты 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
}
}
Это не совсем короткое и сладкое, но оно выразительное, ясное и многоразовое.
Ответ 3
Мне понравилось решение @Keith. Но я думаю, что это не написано в Swift 4, так как я не могу скомпилировать его с помощью компилятора Swift 4.
Поэтому я конвертировал его код в версию Swift 4 здесь.
Помните, что если вы используете более высокую версию языка Swift, чем Swift 4.1, тогда этот ответ не нужен, поскольку он предоставляет эту функцию по умолчанию. Вы можете обратиться сюда для более подробной информации.
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
Ответ 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
.