Swift에서 Comparable 프로토콜은 크기 비교 연산(<, >, <=, >=)을 하기 위해 만들어진 프로토콜입니다.
일반적으로 Comparable 프로토콜은 "<" 연산자만 구현하면 나머지 크기 비교 연산자(>, <=, >=)는 자동으로 구현된다는 특징을 가지고 있습니다.
Comparable 프로토콜은 Equatable 프로토콜을 상속받기 때문에 Equatable 프로토콜의 요구사항 코드를 작성할 필요가 있습니다. (속성이 Equatable 프로토콜을 채택한 타입이라면 작성할 필요가 없지만, 클래스의 경우에는 꼭 작성해야 합니다.)
Comparable 프로토콜의 요구사항 코드는 아래와 같습니다.
static func <(lhs: Self, rhs: Self) -> Bool{
return 동일성 비교 관련 코드
}
Swift에서 기본적으로 제공해주는 기본타입(Int, String, Double 등)은 Comparable 프로토콜을 자동으로 채택하고 있습니다. 때문에 별다른 메서드 구현 없이 크기 비교 연산자를 사용할 수 있습니다.
10 < 4 // false
10 > 4 // true
10 <= 4 // false
10 >= 4 // true
하지만 사용자가 정의한 타입 즉, 커스텀 타입(Enum, Struct, Class)의 경우에는 Comparable 프로토콜을 직접 채택해줘야 크기 비교 연산이 가능합니다.
또한 Comparable 프로토콜은 Equatable 프로토콜과 다르게 특별한 예외가 없다면 "<" 연산자 메서드를 꼭 구현해야 합니다. (열거형은 원시값이 없다면 크기 비교 연산자 메서드를 자동으로 제공)
열거형은 Comparable 프로토콜을 채택한 뒤 크기 비교 연산자 메서드를 구현해야만 크기 비교 연산이 가능합니다.
열거형에 원시값이 없는 경우에는 크기 비교 연산자 메서드를 구현할 필요가 없습니다.
✅ 원시값과 연관값이 없는 경우
원시값과 연관값이 없는 경우에는 Comparable 프로토콜만 채택하면 크기 비교 연산이 가능합니다.
enum number:Comparable{ case one case two case three } number.one < number.two // true number.one > number.three // false number.one <= number.two // true number.one >= number.three // false
✅ 연관값만 있는 경우
연관값만 있는 경우에도 Comparable 프로토콜만 채택하면 크기 비교 연산이 가능합니다.
enum number:Comparable{ case one(Int) case two(Double) case three(Float) } number.one(10) < number.two(20.2) // true number.one(10) > number.three(30.3) // false number.one(10) <= number.two(20.2) // true number.one(10) >= number.three(30.3) // false
✅ 원시값만 있는 경우
열거형에 원시값이 있는 경우에는 Comparable 프로토콜을 채택 후 크기 비교 메서드를 구현해야 합니다.
enum number: Int{ case one case two case three } extension number: Comparable{ static func <(lhs: number, rhs: number) -> Bool{ return lhs.rawValue < rhs.rawValue } } number.one < number.two // true number.one > number.three // false number.one <= number.two // true number.one >= number.three // false
구조체의 모든 저장 속성이 Comparable 프로토콜을 채택한 타입이더라도 크기 비교 연산자 메서드를 꼭 구현해야 합니다.
✅ 구조체의 크기 비교 연산
struct Man{ var name: String var age: Int func hello(){ print("안녕") } } extension Man: Comparable{ static func <(lhs: Man, rhs: Man) -> Bool{ return lhs.age < rhs.age // age만 크기 비교 } } var kim = Man(name: "김철수", age: 25) var shin = Man(name: "신짱구", age: 25) kim < shin // false kim > shin // false kim <= shin // true kim >= shin // true
클래스의 모든 저장 속성이 Comparable 프로토콜을 채택한 타입이더라도 크기 비교 연산자 메서드를 꼭 구현해야 하며, Comparable 프로토콜이 상속받고 있는 Equatable 프로토콜의 요구사항 코드 또한 작성해야 합니다.
✅ 클래스의 크기 비교 연산
class Man: Equatable{ var name: String var age: Int init(name: String, age: Int){ self.name = name self.age = age } func hello(){ print("안녕") } } extension Man: Comparable{ static func == (lhs: Man, rhs: Man) -> Bool { // 필수 구현!! return (lhs.name == rhs.name) && (lhs.age == rhs.age) } static func <(lhs: Man, rhs: Man) -> Bool{ return lhs.age < rhs.age // age만 크기 비교 } } var kim = Man(name: "김철수", age: 25) var shin = Man(name: "신짱구", age: 25) kim < shin // false kim > shin // false kim <= shin // true kim >= shin // true