서론
Equatable과 Identifiable은 비슷하지만 다른 개념입니다.
공식문서에서도 See Also로 Identifiable를 봐보라고 알려주네요.
이 둘에 대해서 처음 들어보신 분도, 익숙하신 분도 계실텐데요.
이번 포스팅에서는 Equatable가 무엇인지 알아보겠습니다.
다음 포스팅에서는 Identifiable에 대해 알아볼 예정이에요!
Equatable
Equatable에 대해 알아봅시다.
Equatable은 프로토콜 중 하나로 값이 같은지 비교할 수 있는 타입입니다.
용어가 낯설다고 생각하시는 분들은 아래 사진을 봐주세요.
개발자라면 낯설 수가 없는 이 부호가 사실 Equatable의 필요 조건이었습니다.
즉, Equatable을 준수하기 위해서는 == 연산자를 통해 "같다"를 정의해야 합니다.
이를 다르게 말하면 프로토콜을 준수하는 타입은 == 연산자와 != 연산자를 이용해 같음을 비교할 수 있습니다.
Swift 표준 라이브러리의 대부분 기본 데이터타입은 Equatable를 따릅니다.
Int, Double, String 등 모두 자연스럽게 == 연산자를 사용해서 특정 값과 같은지 비교하고 있죠.
그렇다면 정말로 기본 데이터타입이 Equtable을 만족하고 있는지 볼까요?
대표로 Int를 살펴보겠습니다.
Int는 FixedWidthInteger과 SignedInteger를 준수하고 있습니다.
Equtable이 나올 때까지 타고 타고 들어가봅시다.
AdditiveArithmetic까지 타고 들어온 결과 Equtable을 만날 수 있었습니다.
참고로 String은 바로 확인할 수 있어요 ㅎㅎ;
참고로 Equtalbe을 상속한 프로토콜은 공식 문서에 잘 나와 있었습니다.
위에서 본 AdditiveArithmetic을 포함하여 이미 여러 프로토콜이 Equtable을 준수하고 있었습니다.
이래도 공부해서 직접 구현할거야? 라고 말하는 거 같지만 어쩔 수야 있겠습니까 ㅎ 공부해야지 ㅎㅎ
기본 데이터 타입이 Equtable을 준수하고 있다는 것을 확인했으니 Equtable 코드도 확인해봅시다.
두 개의 value가 "어떤 기준"에 따라 같은지를 Bool 타입으로 반환합니다.
우리는 이 메서드를 타입에 정의하여 "어떤 기준"을 정해주면 됩니다.
Equatable 실습
Equatable을 실제로 사용해봅시다.
class Custom {
var value: Int
init(_ value: Int) {
self.value = value
}
}
let custom1 = Custom(1)
let custom2 = Custom(2)
value라는 변수를 가진 Custom 클래스를 정의하고 Custom 클래스 인스턴스를 두 개 생성했습니다.
저는 class로 했지만 struct도 가능합니다.
if custom1 == custom2 {
print("same")
} else {
print("different")
}
그리고 조건문을 이용해 둘이 같다면 same을 출력하고 다르다면 different를 출력하게 했습니다.
이 코드를 실행하면 어떻게 될까요?
에러가 발생하게 됩니다.
두 개의 Custom 인스턴스에는 ==를 적용할 수 없다는 의미인데요.
제가 만든 Custom 클래스는 Equtable을 아직 준수하지 않았기 때문에 == 연산자로 비교할 수 없기 때문입니다.
그럼 Equtable을 준수해 봅시다.
class Custom: Equatable {
var value: Int
init(_ value: Int) {
self.value = value
}
static func == (lhs: Custom, rhs: Custom) -> Bool {
return lhs.value == rhs.value
}
}
Equatable을 준수하기 위해 클래스 이름 옆에 프로토콜 이름을 적어주고
== static func를 정의해줍니다.
같다의 기준을 Custom 타입 두 개의 value가 같으면 "같다"로 작성했습니다.
그럼 이제 오류가 사라졌는지 봅시다.
오류도 사라지고 원하는대로 different라고 출력됩니다.
그럼 != 연산자도 가능할까요?
정상적으로 동작합니다!
왜 !=를 정의하지 않았는데 사용이 가능한거야? 라고 생각하시는 분도 있을겁니다. (사실 제가 놀람 ㅎ; 안 될 줄 ㅎㅎ;;;)
위 == 스크린샷을 잘 봐보세요.
Equality is the inverse of inequality. For any values `a` and `b`, `a == b` implies that `a != b` is `false`.
== 만 정의하면 이것의 반대인 !=의 값을 알 수 있기 때문에 ==만 정의해도 != 연산자를 사용할 수 있습니다.
옵셔널 비교
여기서 흥미로웠던 점은 옵셔널 비교입니다.
위 예시처럼 옵셔널과 옵셔널이 아닌 변수를 비교하면 어떻게 될까요?
same이 출력될까요 not same이 출력될까요?
아니면 옵셔널과 non 옵셔널 비교이기 때문에 에러가 발생할까요??
정답은 same이 출력된다입니다!
왜냐하면 옵셔널과 non 옵셔널을 비교하면 non 옵셔널을 옵셔널로 warpping하여 비교하기 때문입니다.
위 링크를 통해 옵셔널 코드를 확인할 수 있었는데요.
참고로 where 문은 Extension에 조건을 추가하는 것으로 특정 조건을 만족시킬때만 기능을 확장시키거나 프로토콜을 채택하도록 제한하는 것입니다.
매개 변수를 옵셔널로 감싸서 비교를 한다는 것을 볼 수 있습니다.
즉, Custom(1)과 Custom(1)?을 비교하면 내부에서는 Custom(1)?과 Custom(1)?을 비교하는 것과 같다는 의미입니다.
그래서 == 연산자도 제대로 동작을 하는 것이고요.
이해가 되셨나요??
contains
contains의 인자로 클래스나 구조체를 전달하기 위해서도 Equtable이 필요합니다.
Equtable을 준수하지 않았을 때 contains가 잘 실행되는지 볼까요?
안타깝게도 "Cannot convert value of type 'Custom' to expected argument type '(Custom) throws -> Bool'" 에러가 발생하네요.
Custom 클래스가 Equtable을 준수하지 않아 contains의 인자로 전달할 수 없는 것입니다.
이 내용도 Equtable 설명에서 찾을 수 있었는데요.
Some sequence and collection operations can be used more simply when the elements conform to `Equatable`. For example, to check whether an array contains a particular value, you can pass the value itself to the `contains(_:)` method when the array's element conforms to `Equatable` instead of providing a closure that determines equivalence. The following example shows how the `contains(_:)` method can be used with an array of strings.
클로저를 전달하는 대신 Equatable을 준수하면 인자로 전달해서 더 쉽게 같음을 비교할 수 있다라고 나와 있습니다.
contains의 공식 문서 내용에도 Element는 Equatable을 준수해야 한다고 나와있네요 ㅎ
말하는대로 Equatable을 준수하니 contains를 정상적으로 사용할 수 있게 되었습니다.
마무리
오늘은 Equtable에 대해 알아보았는데요.
직접 정의한 구조체나 클래스에서 == 연산자를 쓰고 싶을 때 참고하여 구현하시면 유용할 것 같습니다.
다음 포스팅에서는 이와 비슷하지만 다른 Identifiable에 대해서 알아봅시다.
+
오늘 면접에서 Equtable에 대해 아무런 말도 하지 못했습니다. (거의 다 대답 못했긴 했어요 ㅠ)
다음 면접에서도 못 말하면 진짜 문제니까 열심히 공부합시다.
참고
https://developer.apple.com/documentation/swift/equatable
https://developer.apple.com/documentation/swift/identifiable
https://zeddios.tistory.com/227
아직은 초보 개발자입니다.
더 효율적인 코드 훈수 환영합니다!
공감과 댓글 부탁드립니다.