티스토리 뷰

iOS

Swift Hashable Protocol에 대한 10가지 정리

꿀벌의달콤한여행 2021. 4. 30. 18:01

Hashable 프로토콜은 '정수형 해시값으로 자료형을 나타낼 수 있음' 정도의 의미를 가집니다. Swift의 기본 Collection 중 Set, Dictionary는 해시테이블로 구현이 되어있기에 Set의 아이템 Dictionary의 Key로 사용하고자 하는 자료형은 Hashable 프로토콜을 준수해야 합니다. 이외에 Hashable 프로토콜을 공부하면서 정리가 필요했던 몇 가지 부분을 글로 남깁니다.

  1. Hashable 프로토콜은 Swift 4.1 부터 Equatable, Comparable과 마찬가지로 synthesized implement가 생김(특정 조건을 만족한 상태에서 프로토콜을 채택할 경우 프로토콜을 자동으로 구현해주는 것)

  2. Hashable 프로토콜의 synthesized implement 조건은 다음과 같은 3가지 이다.

    • 구조체인 경우, 구조체의 모든 저장 프로퍼티가 Hashable 프로토콜을 준수할 것
    • 열거형인 경우, 모든 associative value가 Hashable 프로토콜을 준수할 것
    • 열거형인 경우, associative value가 없을 것
      (이 3가지 조건은 Equatable 프로토콜에도 동일하게 적용된다)
  3. Swift 4.2 부터 Hashable 프로토콜 구현을 위해 필요한 것이 오직 hash(into:) 메소드 구현으로 바뀌었다(전에는 저장 프로퍼티 hashValue도 구현해야했음).

  4. Swift 4.2 부터 Hasher 구조체가 새로 등장하여, hash(into:) 함수 내에서 해시값 구현이 보다 더 쉽고, 명확(해시값 충돌이 잘 안나도록) 해 졌다.

    func hash(into hasher: inout Hasher) {
     hasher.combine(...)
     hasher.combine(...)
    }
  5. Hasher 구조체는 프로그램이 실행될 때마다 다른 Seed값을 가지고, 값을 feed하는 순서, 어떤 값을 feed하는지에 따라 해시값이 다르게 나온다. 값을 feed하는 것은 Hasher 구조체의 combine(_:) 메소드에 값을 인자로 전달하여 호출하는 것이다. 이후 finalize() 메소드를 통해 해시값을 얻어낼 수 있는데, 이 메소드는 hasher(into:) 메소드를 직접 구현한 경우, 메소드 내에서 호출해서는 안된다. 나중에는 컴파일 에러로 처리가 될 것이다.

  6. hash(into:) 메소드에서 동일한 값을 동일한 순서로 feed할 경우 동일한 해시값이 나온다(단, 프로그램 실행마다 hasher의 Seed 값이 다르기 때문에 동일한 값, 동일한 순서끼리 해시값은 같음이 보장되지만 프로그램 실행 때마다 같음을 보장하진 않음. 그러니 해시값을 저장해서 사용하는 것은 안됨)

  7. hash(into:) 를 synthesized implement하지 않고 직접 구현할 경우, 반드시 essential components를 feed 해야 한다. 중요한 컴포넌트란, 타입 내에서 구현한 ==메소드에서 비교할 때 사용하였던 컴포넌트 들을 말한다. hasher 에게 줄 먹이는 반드시 ==함수에서 구현한 것과 동일해야 한다(비교할 것, 비교 순서도 동일하게)

  8. Hashable 프로토콜은 Equatable 프로토콜을 상속한다.

  9. Hashable 프로토콜을 준수해야 Swift가 제공하는 Collection 중 Set의 아이템, Dictionary의 Key로 사용할 수 있다.

  10. Set, Dictionary는 hash(into:) 메소드에서 얻어낸 해시값이 같은 경우, Equatable 프로토콜은 준수한 결과값(== 메소드 구현)으로 각 아이템이 동일한지를 확인한다.

참고자료
Apple Developer Documentation
https://docs.swift.org/swift-book/LanguageGuide/Protocols.html

댓글