Swift에서 Equatable 프로토콜은 동일성 비교 연산(==, !=)을 하기 위해 만들어진 프로토콜입니다.
일반적으로 Equatable 프로토콜은 "=="연산자 메서드만 구현하면 "!=" 연산자는 컴파일러에 의해 자동으로 구현됩니다.
Equatable 프로토콜의 요구사항 코드는 아래와 같습니다.
static func ==(lhs: Self, rhs: Self) -> Bool{
return 동일성 비교 관련 코드
}
Swift에서 기본적으로 제공해주는 기본타입(Int, String, Double 등)은 Equatable 프로토콜을 자동적으로 채택하고 있습니다. 때문에 별다른 메서드 구현 없이 동일성 비교 연산자를 사용할 수 있습니다.
10 == 10 // true
10 != 10 // false
5.5 == 5.2 // false
5.5 != 5.2 // true
"hello" == "Hello" // false
"hello" != "Hello" // true
하지만 사용자가 정의한 타입 즉, 커스텀 타입(Enum, Struct, Class)의 경우에는 Equatable 프로토콜을 직접 채택해줘야 동일성 비교 연산이 가능합니다.
원칙적으로 열거형의 경우에는 Equatable 프로토콜을 채택해야만 동일성 비교 연산이 가능합니다.
하지만 열거형에 연관값이 없다면 열거형은 기본적으로 Equatable/Hashable하기 때문에 별다른 채택 없이 동일성 비교 연산이 가능합니다. (원시값만 있는 경우에도 별다른 채택 없이 동일성 비교 연산이 가능합니다.)
✅ 연관값이 없는 경우의 동일성 비교 연산
enum number{ case one case two case three } number.one == number.two // false number.one != number.three // true
✅ 연관값이 있는 경우의 동일성 비교 연산
열거형의 모든 연관값이 Equatable 프로토콜을 채택한 타입이라면 비교연산자 메서드가 자동으로 구현됩니다.
enum number: Equatable{ case one(Int) // 연관값이 기본 타입(기본 타입은 Equatable 프로토콜을 자동적으로 채택) case two(Double) case three(Float) // static func ==(lhs: Self, rhs: Self) -> Bool{ 메서드를 구현할 필요가 없음 // return 동일성 비교 관련 코드 // } } number.one(10) == number.two(10.0) // false number.one(5) != number.three(5.5) // true
구조체의 모든 저장 속성이 Equatable 프로토콜을 채택한 타입이라면 비교연산자 메서드가 자동으로 구현됩니다.
✅ 구조체의 동일성 비교 연산
struct Man: Equatable{ var name: String var age: Int func hello(){ print("안녕") } } var kim = Man(name: "김철수", age: 25) var shin = Man(name: "신짱구", age: 25) kim == shin // false kim != shin // true
열거형과 구조체의 메모리 저장공간은 스택(Stack)이지만, 클래스의 저장공간은 힙(Heap)입니다.
클래스의 인스턴스는 스택 공간에 저장되는 것이 아닌 힙 공간에 저장됩니다. 때문에 비교할 때는 항등연산자(===)를 사용하여 주소값을 비교합니다. (사실 클래스는 동일성 비교 연산이 불가능하게 만들어진 타입입니다.)
이러한 이유?로 클래스의 모든 저장 속성이 Equatable 프로토콜을 채택한 타입일지라도 비교연산자 메서드를 꼭 구현해야 합니다.
✅ 클래스의 동일성 비교 연산
class Man: Equatable{ var name: String var age: Int init(name: String, age: Int){ self.name = name self.age = age } func hello(){ print("안녕") } static func == (lhs: Man, rhs: Man) -> Bool { // 필수 구현!! return (lhs.name == rhs.name) && (lhs.age == rhs.age) } } var kim = Man(name: "김철수", age: 25) var shin = Man(name: "신짱구", age: 25) kim == shin // false kim != shin // true