我想测试两个Swift enum值的相等性。例如:
enum SimpleToken {
case Name(String)
case Number(Int)
}
let t1 = SimpleToken.Number(123)
let t2 = SimpleToken.Number(123)
XCTAssert(t1 == t2)
但是,编译器不会编译等式表达式:
error: could not find an overload for '==' that accepts the supplied arguments
XCTAssert(t1 == t2)
^~~~~~~~~~~~~~~~~~~
我需要自己定义重载的相等运算符吗?我希望Swift编译器能自动处理它,就像Scala和Ocaml那样。
斯威夫特4.1 +
正如@jedwidz指出的那样,从Swift 4.1开始(由于SE-0185, Swift还支持为枚举合成相关值的Equatable和Hashable。
因此,如果您使用的是Swift 4.1或更新版本,下面将自动合成必要的方法,以便XCTAssert(t1 == t2)工作。关键是将Equatable协议添加到枚举中。
enum SimpleToken: Equatable {
case Name(String)
case Number(Int)
}
let t1 = SimpleToken.Number(123)
let t2 = SimpleToken.Number(123)
Swift 4.1之前
正如其他人所注意到的,Swift不会自动合成必要的相等操作符。不过,让我提出一个更清晰的实现:
enum SimpleToken: Equatable {
case Name(String)
case Number(Int)
}
public func ==(lhs: SimpleToken, rhs: SimpleToken) -> Bool {
switch (lhs, rhs) {
case let (.Name(a), .Name(b)),
let (.Number(a), .Number(b)):
return a == b
default:
return false
}
}
这远非理想——有很多重复——但至少你不需要在if语句里面做嵌套开关。
扩展mbpro的答案,下面是我如何使用该方法在一些边缘情况下检查swift枚举与相关值的相等性。
当然,你也可以使用switch语句,但有时最好只检查一行中的一个值。你可以这样做:
// NOTE: there's only 1 equal (`=`) sign! Not the 2 (`==`) that you're used to for the equality operator
// 2nd NOTE: Your variable must come 2nd in the clause
if case .yourEnumCase(associatedValueIfNeeded) = yourEnumVariable {
// success
}
如果你想比较同一个If子句中的两个条件,你需要使用逗号而不是&&操作符:
if someOtherCondition, case .yourEnumCase = yourEnumVariable {
// success
}
enum MyEnum {
case none
case simple(text: String)
case advanced(x: Int, y: Int)
}
func ==(lhs: MyEnum, rhs: MyEnum) -> Bool {
switch (lhs, rhs) {
case (.none, .none):
return true
case let (.simple(v0), .simple(v1)):
return v0 == v1
case let (.advanced(x0, y0), .advanced(x1, y1)):
return x0 == x1 && y0 == y1
default:
return false
}
}
对于枚举和结构,似乎没有编译器生成的相等操作符。
例如,如果你创建了自己的类或结构来表示一个复杂的数据模型,那么这个类或结构的“等于”的含义就不是Swift能帮你猜出来的。”[1]
要实现相等性比较,可以这样写:
@infix func ==(a:SimpleToken, b:SimpleToken) -> Bool {
switch(a) {
case let .Name(sa):
switch(b) {
case let .Name(sb): return sa == sb
default: return false
}
case let .Number(na):
switch(b) {
case let .Number(nb): return na == nb
default: return false
}
}
}
[1]参见https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_43的“等价运算符”