ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Swift - Hashable Protocol
    Programming/Swift 2022. 1. 16. 19:38

     

    안녕하세요 BeePeach입니다 :)

     

    오늘은 기본적인 Protocol 중에 마지막 Hashable 프로토콜에 대해서 공부해보려고 합니다.

     

     

    출처 :https://ko.wikipedia.org/wiki/해시_함수

    여기서 Hash란 아주 간단하게 설명하자면 어떠한 값을 특정 알고리즘을 통해서 Integer값으로 변환시키는 것을 의미합니다.

    변환 알고리즘에는 종류가 아주 많습니다! (심심하면 한번 찾아보셔도 좋습니다.. SHA가 유명합니다.)

    위 그림은 문자열을 특정 알고리즘함수를 통해서 00 ~ 15까지 변환하는 작업을 표현했습니다.

    그리고 2개의 값이 다른데 같은 hash값으로 변환된 문제를 그림으로 표현한 것입니다. (이를 collision이라고 합니다.)

    암호화에 사용하고 어쩌구 저쩌구 이런 건 다 제쳐두고 간단하게 어떤 값을 Interger값으로 변환시키는거구나~ 라고만 알고 넘어가도록 하죠!

     

    Hash를 이용하면 테이블을 생성하게 되는데 변환된 hashValue를 Index로 하여 변환 전의 데이터를 찾을 수 있어서 검색에 걸리는 시간이 O(1)으로 매우 빨라지게 됩니다.

    그럼 이걸 어디에 이용할까요??

     

    Dictionary의 Key 그리고 Set에는 아무 값이다 다 들어갈 수 있는 게 아닙니다.

    Hashable 프로토콜을 채용한 Type만 사용할 수 있습니다.

    Int, String 등을 key 또는 Set에서 사용할 수 있던 것은 standard library에서 제공하는 몇몇 Type들이 Hashable 프로토콜을 채용하고 있었기 때문입니다.

    그럼 Custom Type이 Dictionary의 Key 또는 Set으로 사용되려면 Hasable 프로토콜을 준수하도록 해야겠죠?

     

    같이 한번 공부해보도록 하겠습니다.

     

     


     

    Adopting a Protocol Using a Synthesized Implementation

     

    Swift에서는 언제  Hash 프로토콜의 synthesized implementation를 제공해줄까요??

    Equtable 프로토콜과 똑같은 경우에 제공을 해줍니다.

    • Structure가 Hashable 프로토콜을 채용하는 stored property만을 가지고 있을 때
    • Enumeration이 associated value를 가지고 있지 않을 때
    • Enumeration이 Hashable protocol을 채용한 associated value만을 가지고 있을 때

     

     

    Class는 매번 소외당하는군요ㅠㅠ

    그럼 Hashable 프로토콜이 뭔지부터 확인해 봐야겠죠?

     

     


     

    Hashable

     

    설명에서는 정수 해시값을 생성할 수 있는 Type이라고 나와있습니다.

    맨 처음 설명에서 hash란 어떤 값을 Interger로 바꾸는 것이라고 했었죠?? 

    이 프로토콜을 채용하면 필요할 때 Swift가 알아서 인스턴스를 정수인 hash value로 변환시켜줍니다.

     

    재밌는 점은 Equatable 프로토콜을 상속하고 있다는 점입니다.

    Comparable 프로토콜은 대소 비교를 하는 것이기 때문에 Equtable이 전제조건으로 들어가야 한다는 건 납득이 가능한데

    Hashable 프로토콜은 왜 Equtable이 필요할까요??

    바로 hash value로 변환시킬 때 같은 값의 인스턴스는 Hasher에 같은 값을 전달해야 하기 때문입니다.

    예를 들어 "BeePeach"를 전달했는데 어떤 때는 hash value가 100이고 어떤때는 200이면 안 되겠죠?

    같은 값이면 hash value는 같은 값을 가지고 있어야 하기 때문입니다.

     

     

    필수 요구사항은 얼핏 보면 2개인 것처럼 보이지만 hashValue옆을 잘 보면 Deprecated라고 되어있습니다.

    즉 지금은 사용하고 있지 않는 프로퍼티입니다.

    그래서 hash(into:) 메서드만 구현해주면 됩니다.

     

     


     

    Class

     

     

    Person 클래스를 생성하고 beepeach인스턴스를 생성한 다음 dictionary의 value로 넣어봤습니다.

    전혀 문제가 없네요??

    근데 dictionary의 key로 넣으니까 에러가 발생하는 것을 확인할 수 있습니다.

    에러 메시지를 확인해보니 Person이 Hashable을 준수하고 있지 않다고 합니다.

    그럼 한번 에러를 고쳐볼까요??

     

     

    에러가 말끔하게 사라진 것을 확인할 수 있습니다.

    구현을 살펴보도록 하죠.

     

    먼저 Hashable이 Equtable을 상속하고 있기 때문에 == 연산자를 정의해줘야 합니다.

    그리고 Hashable의 필수 요구사항인 hash(into:) 메서드를 구현해줬습니다.

     

    이 hash(into:) 메서드에서 파라미터로 전달된 hasher가 제공하는 combine() 메서드를 호출해서 stored property들을 하나하나 전달해주면 됩니다.

    아주 간단하죠???

     

     


     

    Structrue

     

    Struct의 경우에는 모든 저장 프로퍼티가 Hashable을 채용하고 있는 Type이라면 synthsized implementation이 제공됐었죠??

    그럼 구현 방법은 Comparable에서 공부한 것과 같이 아주 간단해집니다.

     

     

    Hashable을 채용하기만 하면 == 연산자의 구현과 hash(into:)의 구현이 알아서 제공됩니다.

    만약 저장 프로퍼티에 Hashable을 제공하지 않는 Type이 들어간다면 Class에서 구현한 것처럼 추가해주면 됩니다.

     

     


     

    Enumeration

     

    Enum의 경우에도 synthsized implementation이 제공되는 경우가 존재했습니다.

    Associated value을 가지지 않고 기본 구현이나 RawValue만을 가지고 있을 때는 Hashable을 채용하지 않아도 자동적으로 Hashable을 채용하고 있습니다.

     

     

    Hashable을 채용하고 있지 않는데 dictionary의 key로 사용해도 아무런 에러가 발생하지 않는 것을 확인할 수 있습니다.

    그럼 마지막으로 Hashable을 채용하고 있지 않는 Type을 가지는 associated value가 있는 경우를 살펴보겠습니다.

     

     

    이 예시에서는 Company 클래스를 구현하고 Equtable프로토콜을 채용하도록 했습니다.

    그리고 Transportation 열거형을 구현했습니다.

    taxi case에서 Hashable 프로토콜을 채용하지 않는 Company가 들어가 있기 때문에 직접 Hashable을 만족하도록 해줘야 합니다.

    그래서 extension을 이용해서 hash(into:) 메서드를 구현했는데 결국 에러가 발생했습니다.

     

    바로 Company에 Hashable 구현을 해주지 않았기 때문입니다.

     

     

    Company가 Hashable을 준수하도록 코드를 바꿔줬습니다.

    이렇게 되면 Transportation의 모든 associated value가 Hashable을 채용하고 있기 때문에 간단하게 채용만 해주는 것으로 기본 구현을 제공받을 수 있게 됩니다.

    그래서 기존에 extension으로 구현했던 hash(into:)을 삭제시켜주어도 dictionary의 key로 사용할 수 있는 것을 확인할 수 있습니다.

    (이 구현을 삭제해도 에러가 나지 않지만 어떤 다른 문제 발생 가능성이 생기는지 알아보려 했는데 제대로 된 설명을 찾지 못했습니다. 혹시 hash(into:)를 삭제한 것으로 문제가 발생한다면 댓글로 알려주시면 감사하겠습니다! )

     

     


     

    참고 자료

     

    https://docs.swift.org/swift-book/LanguageGuide/Protocols.html

     

    Protocols — The Swift Programming Language (Swift 5.5)

    Protocols A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of tho

    docs.swift.org

     

     

    https://developer.apple.com/documentation/swift/hashable

     

    Apple Developer Documentation

     

    developer.apple.com

     

     

    https://kxcoding.com

     

    여러분의 새로운 도전을 응원합니다 | KxCoding

    Mastering SwiftUI 더 적은 코드로, 더 멋진 UI 만들기

    kxcoding.com

     

     


     

    728x90

    'Programming > Swift' 카테고리의 다른 글

    Swift - Generic Type  (0) 2022.01.18
    Swift - Generic  (0) 2022.01.17
    Swift - Comparable Protocol  (0) 2022.01.15
    Swift - Equatable Protocol  (0) 2022.01.14
    Swift - Protocol Extension  (0) 2022.01.12
Designed by Tistory.