[Swift] Comparable, Equatable, Hashable 및 주요 프로토콜 정리

Swiftios
avatar
2025.02.26
·
5 min read

Swift에서 프로토콜(Protocol)은 특정 기능을 정의하고, 이를 여러 타입에서 구현하도록 하는 강력한 개념이다.

그 중에서도 Comparable, Equatable, Hashable같은 기본 프로토콜들은 정렬, 비교, 딕셔너리 키 활용 등 다양한 기능을 제공한다.

Comparable 프로토콜

Comparable이란?

Comparable은 값을 비교할 수 있도록 해주는 프로토콜이다.

이를 준수하면 >(크다), <(작다), >=(크거나 같다), <=(작거나 같다) 등의 비교 연산자를 사용할 수 있다.

Comparable 프로토콜 구현하기

Person 구조체에서 Comparable 적용

static func <를 구현하여 나이를 기준으로 비교 가능

struct Person: Comparable {
    let name: String
    let age: Int

    static func < (lhs: Person, rhs: Person) -> Bool {
        return lhs.age < rhs.age
    }
}

Comparable을 활용한 정렬

sorted()함수를 사용하면 자동으로 나이를 기준으로 정렬됨

정렬 기준을 커스텀하고 싶다면 sorted(by:)를 활용

let sortedByName = people.sorted { $0.name < $1.name }

Equatable 프로토콜

  • 두 개의 객체를 비교할 수 있도록 하는 프로토콜

  • == 연산자를 사용할 수 있게 해줌

기본 타입들은 Equatable을 자동으로 채택

let a = 5
let b = 5
print(a == b) // true (Int는 기본적으로 Equatable)

사용자 정의 타입에서 Equatable 구현

struct User: Equatable {
    let id: Int
    let name: String
}

Equatable을 준수하는 경우, Swift가 자동으로 ==를 구현

let user1 = User(id: 1, name: "춘장")
let user2 = User(id: 2, name: "메주")

print(user1 == user2) // false

비교 연산이 필요한 경우 Equatable을 적용하는 것이 필수!

Hashable 프로토콜

  • 객체를 해시 값으로 변환할 수 있도록 하는 프로토콜

  • Dictionary 또는 Set의 키로 사용할 수 있도록 함

Hashable을 구현하면 Dictionary의 키로 사용 가능

Dictionary에서 키로 활용할 때 Hashable을 적용하면 효율적인 검색이 가능

struct Product: Hashable {
    let id: Int
    let name: String
}

var productSet: Set<Product> = []
productSet.insert(Product(id: 1, name: "MacBook"))
productSet.insert(Product(id: 2, name: "iPhone"))

print(productSet.contains(Product(id: 1, name: "MacBook"))) // true

Custom Hash Function을 만들 수도 있음

struct CustomUser: Hashable {
    let id: Int
    let username: String

    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
        hasher.combine(username)
    }
}

Codable (Encodable & Decodable) 프로토콜

  • JSON과 Swift 객체 간 변화를 쉽게 해주는 프로토콜

  • API 통신 시 데이터를 직렬화(Serialize)하거나 역직렬화(Deserialize)할 때 사용

Codable을 활용한 JSON 디코딩 예제

Codable을 사용하면 JSON 데이터를 Swift 구조체로 쉽게 변환 가능

struct User: Codable {
    let id: Int
    let name: String
}

let jsonData = """
{
    "id": 1,
    "name": "감태"
}
""".data(using: .utf8)!

let user = try? JSONDecoder().decode(User.self, from: jsonData)
print(user?.name) // "감태"

Sequence & Collection 프로토콜

  • 배열과 같은 컬렉션을 구현할 때 필요한 프로토콜

  • for-in 루프를 사용할 수 있도록 해줌

Sequence 프로토콜 구현

Sequence를 활용하면 사용자 정의 반복 구조를 만들 수 있음

struct Countdown: Sequence, IteratorProtocol {
    var count: Int

    mutating func next() -> Int? {
        if count == 0 {
            return nil
        } else {
            defer { count -= 1 }
            return count
        }
    }
}

let countdown = Countdown(count: 5)
for number in countdown {
    print(number) // 5, 4, 3, 2, 1 출력
}

CustomStringConvertible 프로토콜

  • 객체를 문자열로 변환할 때 사용

  • print() 시 커스텀 문자열을 출력 가능

객체의 출력 형식을 사용자 정의할 수 있어 디버깅에 유용

struct Car: CustomStringConvertible {
    let brand: String
    let model: String

    var description: String {
        return "🚗 \(brand) \(model)"
    }
}

let myCar = Car(brand: "Tesla", model: "Model S")
print(myCar) // 🚗 Tesla Model S






- 컬렉션 아티클