두 개의 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처럼 자동으로 처리하기를 바랐습니다.
답변
스위프트 4.1 이상
마찬가지로 @jedwidz가 유용하게 스위프트 4.1 (인해, 지적 SE-0185 , 스위프트 또한 합성 지원 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)
스위프트 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 문으로 중첩 스위치를 수행 할 필요는 없습니다.
답변
구현 Equatable
은 과도한 IMHO입니다. 많은 경우와 많은 다른 매개 변수가있는 복잡하고 큰 열거 형이 있다고 상상해보십시오. 이 매개 변수들도 모두 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/에서 확인 하십시오.
답변
열거 형이나 구조체에 대해 컴파일러에서 항등 연산자를 생성하지 않은 것 같습니다.
“예를 들어 복잡한 데이터 모델을 표현하기 위해 고유 한 클래스 또는 구조를 생성하는 경우 해당 클래스 또는 구조에 대한”동일 “의 의미는 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의 “등가 연산자”를 참조하십시오.
답변
다른 옵션이 있습니다. 구문을 사용하여 중첩 된 switch 문을 피한다는 점을 제외하면 주로 다른 것과 동일 if case
합니다. 나는 이것이 약간 더 읽기 쉽고 (/ 견딜 수 있음) 기본 사례를 피하는 이점을 가지고 있다고 생각합니다.
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
}
}
답변
단위 테스트 코드 에서이 간단한 해결 방법을 사용하고 있습니다.
extension SimpleToken: Equatable {}
func ==(lhs: SimpleToken, rhs: SimpleToken) -> Bool {
return String(stringInterpolationSegment: lhs) == String(stringInterpolationSegment: rhs)
}
문자열 보간을 사용하여 비교를 수행합니다. 프로덕션 코드에는 권장하지 않지만 간결하고 단위 테스트 작업을 수행합니다.
답변
다른 옵션은 케이스의 문자열 표현을 비교하는 것입니다.
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