![]() |
坏坏的眼镜 · 【Unity】2D ...· 1 月前 · |
![]() |
怕老婆的鸡蛋 · 最新消息!事关沈阳地铁3号线!试运行时间预计 ...· 1 月前 · |
![]() |
爱搭讪的饼干 · 女主持家中遇害,却只被偷走一个钱包,凶手死后 ...· 5 月前 · |
![]() |
酷酷的牛腩 · 泛站南片区,高新和平到底是一所怎样的学校?_ ...· 7 月前 · |
![]() |
飘逸的课本 · 我市调整幼儿园收费政策 今年秋季开始执行 ...· 10 月前 · |
![]() |
温暖的电梯 · 博士一般需要读几年才能毕业?毕业之后是不是要 ...· 1 年前 · |
我想测试两个Swift枚举值是否相等。例如:
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做的那样。
t1和t2不是数字,它们是具有关联的值的SimpleTokens的实例。
你可以说
var t1 = SimpleToken.Number(123)
然后你可以说
t1 = SimpleToken.Name(“Smith”)
没有编译器错误。
要从t1检索值,请使用switch语句:
switch t1 {
case let .Number(numValue):
println("Number: \(numValue)")
case let .Name(strValue):
println("Name: \(strValue)")
}
您可以使用switch进行比较
enum SimpleToken {
case Name(String)
case Number(Int)
let t1 = SimpleToken.Number(123)
let t2 = SimpleToken.Number(123)
switch(t1) {
case let .Number(a):
switch(t2) {
case let . Number(b):
if a == b
println("Equal")
default:
println("Not equal")
default:
println("No Match")
}
Swift 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不会自动合成必要的相等运算符。不过,让我提出一个更干净的(IMHO)实现:
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语句中做嵌套开关。
我在单元测试代码中使用了这个简单的解决方法:
extension SimpleToken: Equatable {}
func ==(lhs: SimpleToken, rhs: SimpleToken) -> Bool {
return String(stringInterpolationSegment: lhs) == String(stringInterpolationSegment: rhs)
}
它使用字符串插值来执行比较。我不推荐将其用于生产代码,但它非常简洁,并且可以完成单元测试的工作。
与被接受的答案相比,“优势”在于,“main”switch语句中没有“default”case,因此如果您使用其他case扩展枚举,编译器将强制您更新其余代码。
enum SimpleToken: Equatable {
case Name(String)
case Number(Int)
extension SimpleToken {
func isEqual(st: SimpleToken)->Bool {
switch self {
case .Name(let v1):
switch st {
case .Name(let v2): return v1 == v2
default: return false
case .Number(let i1):
switch st {
case .Number(let i2): return i1 == i2
default: return false
func ==(lhs: SimpleToken, rhs: SimpleToken)->Bool {
return lhs.isEqual(rhs)
let t1 = SimpleToken.Number(1)
let t2 = SimpleToken.Number(2)
let t3 = SimpleToken.Name("a")
let t4 = SimpleToken.Name("b")
t1 == t1 // true
t1 == t2 // false
t3 == t3 // true
t3 == t4 // false
t1 == t3 // false
这里有另一个选择。除了通过使用
if case
语法避免了嵌套的switch语句之外,它与其他方法基本相同。我认为这使得它更具可读性(/bearable),并且具有完全避免缺省情况的优点。
enum SimpleToken: Equatable {
case Name(String)
case Number(Int)
extension SimpleToken {
func isEqual(st: SimpleToken)->Bool {
switch self {
case .Name(let v1):
if case .Name(let v2) = st where v1 == v2 { return true }
case .Number(let i1):
if case .Number(let i2) = st where i1 == i2 { return true }
return false
func ==(lhs: SimpleToken, rhs: SimpleToken)->Bool {
return lhs.isEqual(rhs)
let t1 = SimpleToken.Number(1)
let t2 = SimpleToken.Number(2)
let t3 = SimpleToken.Name("a")
let t4 = SimpleToken.Name("b")
t1 == t1 // true
t1 == t2 // false
t3 == t3 // true
t3 == t4 // false
t1 == t3 // false
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
}
另一个选择是比较大小写的字符串表示:
XCTAssert(String(t1) == String(t2))
例如:
let t1 = SimpleToken.Number(123) // the string representation is "Number(123)"
let t2 = SimpleToken.Number(123)
let t3 = SimpleToken.Name("bob") // the string representation is "Name(\"bob\")"
String(t1) == String(t2) //true
String(t1) == String(t3) //false
另一种使用带逗号的
if case
的方法,在Swift 3中有效:
enum {
case kindOne(String)
case kindTwo(NSManagedObjectID)
case kindThree(Int)
static func ==(lhs: MyEnumType, rhs: MyEnumType) -> Bool {
if case .kindOne(let l) = lhs,
case .kindOne(let r) = rhs {
return l == r
if case .kindTwo(let l) = lhs,
case .kindTwo(let r) = rhs {
return l == r
if case .kindThree(let l) = lhs,
case .kindThree(let r) = rhs {
return l == r
return false
}
这就是我在我的项目中写的。但是我不记得我是从哪里得到这个想法的。(我刚才谷歌了一下,没看到这样的用法。)如有任何意见,我们将不胜感激。
实现
Equatable
是一种过度的杀伤力。假设你有一个复杂而庞大的枚举,它有很多种情况和很多不同的参数。这些参数也都必须实现
Equatable
。此外,谁说您在全有或全无的基础上比较枚举用例?如果您正在测试值,并且只存根了一个特定的枚举参数,该怎么办呢?我强烈建议使用简单的方法,比如:
if case .NotRecognized = error {
// Success
} else {
XCTFail("wrong error")
}
..。或者在参数求值的情况下:
if case .Unauthorized401(_, let response, _) = networkError {
XCTAssertEqual(response.statusCode, 401)
} else {
XCTFail("Unauthorized401 was expected")
}
在这里可以找到更详细的描述: https://mdcdeveloper.wordpress.com/2016/12/16/unit-testing-swift-enums/
扩展了mbpro的答案,下面是我如何使用这种方法来检查带有一些边缘情况的关联值的快速枚举的等价性。
当然,您可以执行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
}
![]() |
酷酷的牛腩 · 泛站南片区,高新和平到底是一所怎样的学校?_手机新浪网 7 月前 |