问题
I have a very simple class in a Playground in Swift 4.0 that overrides the == operator.
I'm not understanding why the Swift complier doesn't behave the same when the class inherits/doesn't inherit Equatable protocol.
Here the class when inheriting Equatable protocol
class Test: Equatable {
var value = 0
init(_ initialValue:Int) {
value = initialValue
}
static func == (lhs:Test, rhs:Test) -> Bool {
return lhs.value == rhs.value ? true : false
}
}
let test1 = Test(0)
var test4:Test? = nil
if test1 == test4 {
print("test1 and test4 are equals")
} else {
print("test1 not equals to test4")
}
When this code executes it displays "test1 not equals to test4". It's the expected behavior.
Next, when I just remove the "Equatable" protocol from the class
class Test {
var value = 0
init(_ initialValue:Int) {
value = initialValue
}
static func == (lhs:Test, rhs:Test) -> Bool {
return lhs.value == rhs.value ? true : false
}
}
let test1 = Test(0)
let test3 = Test(0)
var test4:Test? = nil
if test1 == test4 {
print("test1 and test4 are equals")
} else {
print("test1 not equals to test4")
}
I get a compilation error on the line
if test1 == test4 {
with the following message: "Value of optional type 'Test?' not unwrapped; did you mean to use "!" or '?'?
Why the behavior is different with/without Equatable?
In fact, I was also expecting the same compilation error when the class inherits from Equatable because I compare a non-optional with an optional.
Is it safe to compare a non-optional with an optional when a class inherits Equatable ?
回答1:
There is a == operator
public func ==<T>(lhs: T?, rhs: T?) -> Bool where T : Equatable
which allows to compare two optional values if the underlying
type is Equatable
. That operator is called in your first case
let test1 = Test(0)
var test4:Test? = nil
if test1 == test4 { ... }
(and the left operand is automatically wrapped into an optional.)
If Test
does not conform to Equatable
then that operator does
not match, so that there is no ==
operator taking two Test?
operands. Therefore the compiler error.
回答2:
If you command click on the one that conforms to Equatable it would take you to here:
/// ....
/// You can also use this OPERATOR TO COMPARE A NON-OPTIONAL VALUE TO AN
/// OPTIONAL that wraps the same type. The non-optional value is wrapped as an
/// optional before the comparison is made. In the following example, the
/// `numberToMatch` constant is wrapped as an optional before comparing to the
/// optional `numberFromString`:
///
/// let numberToFind: Int = 23
/// let numberFromString: Int? = Int("23") // Optional(23)
/// if numberToFind == numberFromString {
/// print("It's a match!")
/// }
/// // Prints "It's a match!"
///
/// ....
public func ==<T>(lhs: T?, rhs: T?) -> Bool where T : Equatable
But for the version that doesn't conform to Equatable, you don't get this. It will only use the static function you provided.
来源:https://stackoverflow.com/questions/47059252/why-swift-compiler-behaves-differently-with-equality-operator-with-without-equat