all white cheat sheet Dana’s Swifty Life

Equality vs. Identity - Protocol Equatable & Comparable

:pushpin: Table of Contents

  • equality vs. identity
  • Equatable protocol
  • Comparable protocol

:mag: equality vs. identity

두 상수나 변수가 같다/다르다 - 판단하는 기준

equality (동일성)

관찰 가능한 특징으로서 두 인스턴스가 동일한 값(value)를 가질 때

==, != 로 체크 가능

identity (정체성)

메모리 상에서 같은 instance를 가리킬 때

=== 로 체크 가능

 

value type 끼리 비교하기

Equality :ok_woman: Identity :no_good:

  • value type 은 메모리 기준으로 비교 불가. 값으로 항상 전달되기 때문에
  • Swift standard library에서 정의한 value type이외에 다른 value type의 equality를 custom 하고 싶다면 Hashable, Equatable protocol 채택을 고려해야 함.
  • Hashable 은 판별기준이 되는 value를 구분해주기 위한 hash value를 생성하기 위해 필요한 protocol

reference type 끼리 비교하기

Equality, Identity 둘 다 :ok_woman:

  • Reference type은 전달시, instance가 있는 메모리 위치에 참조를 추가하는 방식이므로 identity는 원래 가능

  • Equality 도 비교하고 싶다면 Equatable protocol을 준수해야 함.

    • 구현에서 equality 를 비교할 판단기준이 될 value를 명시해 주어야 함

 


Equatable protocol

A type that can be compared for value equality

value가 같은지, 다른지 비교가 가능한 type의 자격요건을 담은 protocol

protocol Equatable
  • swift 에서 대부분의 basic typ이 Equatable protocol을 준수한다

 

Equatable protocol 준수하기

Conforming to the Equatable Protocol

  1. 자동으로 conform하는 경우

    • struct : 모든 property가 Equatable 준수
    • enum with associated value: value type이 Equatable 준수하면 가능
    • enum without associated value : 선언 없이도 자동으로 준수
  2. 직접 conformance 구현해야 하는 경우

    방법 : Required function 을 구현한다.

    static func == (lhs: Self, rhs: Self) -> Bool
    
    • infix (중위 연산자)
    • !=== 의 부정으로 자동으로 설정됨
    • Example
    struct Sneakers {
    	let brand: String
      let modelNumber: Int
      let size: Int
    }
       
    extension Sneakers: Equatable {
      static func ==(ls: Sneakers, rs: Sneakers) -> Bool {
        return ls.brand == rs.brand && ls.modelNumber == rs.modelNumber
                && ls.size == rs.size
      }
    }
    
    let listOfSneakers = [Sneakers(brand: "pfflyers", modelNumber: 930905, size: 240),
                         Sneakers(brand: "nike", modelNumber: 789011, size: 235),
                         Sneakers(brand: "pfflyers", modelNumber: 123456, size: 240)]
    let mySneakers = Sneakers(brand: "pfflyers", modelNumber: 930905, size: 240)
       
    for sneakers in listOfSneakers {
      print(sneakers == mySneakers)
    }
    // true, false, false
    

Hashable, Comparable 의 Base protocol (Equatable protocol을 상속받은 protocol)

 


Comparable

A type that can be compared using the relational operators <, <=, >=, and >

비교 연산자로 비교가 가능한 type의 자격요건을 담은 protocol

protocol Comparable

비교가 가능하다

= 순서가 있다 (두 변수/상수 중에 어떤 것이 더 작다/크다)

 = sort() 가 가능하다

 

Comparable protocol 준수하기

Conforming to the Comparable protocol

<== 규칙 구현하면 모든 순서가 생긴다

나머지 비교 연산자는 <, == 을 사용해서 구현할 수 있다

두 operation은 static function으로 선언되어 있다.

  1. == : Comparable protocol은 Equatable protocol을 준수한다

    extension Comparable: Equatable
    
  2. < : Required function 구현하기

    static func < (lhs: Self, rhs: Self) -> Bool
    

    Example : Date struct 에 conformance 추가하기

    struct Date {
      let year: Int
      let month: Int
      let day: Int
    }
       
    extension Data: Comparable {
      static func < (lhs: Date, rhs: Date) -> Bool {
        if lhs.year != rhs.year {
          return lhs.year < rhs.year
        } else if lhs.month != rhs.month {
          return lhs.month < rhs.month
        } else if lhs.day != rhs.day {
          return lhs.day < rhs.day
        }
      }
         
      // since Comparable extends Equatable protocol
      static func == (lhs: Date, rhs: Date) -> Bool {
        return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day
      }
         
      // 나머지 연산자는 ==, <를 사용해서 모두 구현 가능
      // 자동으로 만들어짐? 
      static func <= (lhs: Date, rhs: Date) -> Bool {
      	return lhs == rhs || lhs < rhs
      }
         
      static func > (lhs: Date, rhs: Date) -> Bool {
        return !(lhs < rhs)
      }
         
      static func >= (lhs: Date, rhs: Date) -> Bool {
        return !(lhs < rhs) || lhs == rhs
      }
    }
    
    let myBday = Date(year: 1993, month: 9, day: 5)
    let yourBday = Date(year: 1993, month: 2, day: 28)
       
    if myBday < yourBday {
      print("my birthday is earlier than yours") 
    } else {
      print("my birthday is not earlier than yours") // this statement will be executed 
    }
    

    < 구현 논리 : 각 property에 대해, 같지 않으면, 왼쪽 < 오른쪽 인가?

 


정리

  1. Equality 는 value 가 같은지/다른지

    Indentity 는 메모리상의 instance 위치/주소가 같은지/다른지

  2. Equatable 은 type이 같은지/다른지 비교할 수 있는 능력을 가지게 해줌

    == 연산자를 구현하여 준수한다

  3. Comparable 은 type의 순서를 정할 수 있는 능력을 가지게 해줌

    비교 연산자를 구현하여 준수한다

 

Reference

Equatable protocol - 공식문서

Equatable protocol - source code

Comparable protocol - 공식문서

Comparable protocol - source code

equlity vs. identity - 빅 너드 랜치의 스위프트 프로그래밍