[TIL]06.14

rbw·2022년 6월 14일
0

TIL

목록 보기
25/97
post-thumbnail

Protocol Extension

프로토콜만 선언을 한다면, 내부 함수에 구현까지는 작성이 불가능하다. 이를 개선하기 위해서는 Extension을 활용하면 되는데, 프로토콜과 익스텐션의 조합은 꽤 유용하게 사용되고 있다.

위의 방법으로 프로토콜을 만들고 이 프로토콜을 채택만 하기만 해도, 해당 객체는 프로토콜의 함수를 사용이 가능하다. (마치 상속과 같음) 하지만 익스텐션에서 저장 프로퍼티는 구현이 불가하므로, 객체에서 따로 해줘야 한다.

만약, 타입의 특성에 맞게, 함수의 내용을 변경하고 싶다면 해당 프로토콜을 채택한 객체 내부에서 재정의(오버라이딩)를 해주면 된다.

// 프로토콜을 선언 하고
protocol Talkable {
    func talk(_ person: String)
}

// 내부 구현을 extension에서 해준다.
extension Talkable {
    func talk(_ person: String) {
        print("hello \(person)")
    }
}

struct Person : Talkable {
    var saram: String

    // 재정의한 함수
    func talk() {
        print("my name is \(saram)")
    }
}

let james = Person(saram: "James")

james.talk("minsu") // "hello minsu"
james.talk() // "my name is James"

프로토콜 지향 프로그래밍의 컨셉중 하나가 위와 같이 채택만으로도 기능을 추가할 수 있다는 점이다.

기본 타입의 확장

추가로 Int, String 등등 기본 타입에 확장을 해줄 수 있다.

protocol TypeExtension {
    func myType()
}
extension TypeExtension {
    func myType() {
        print(type(of: self))
    }
}
extension Int : TypeExtension {}
extension String : TypeExtension {}

3.myType() //  Int
"hello".myType() // String 

Associated Type

이는, Protocol의 일부로, 사용되는 타입을 위한 Placehloder 역할을 한다. 정의하는 프로토콜의 채택되기 전까지 실제 타입이 명시되지 않는다.

protocol Container {
    associatedtype Item
    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(i: Int) -> Item { get }
}

위 프로토콜은 3가지의 요구사항을 정의하고 있다.

  1. append(_:) 메소드를 통해 컨테이너에 새로운 항목을 추가 할 수 있어야 한다
  2. Int 타입을 리턴하는 count 프로퍼티를 통해서 컨테이너에 들어있는 항목의 개수를 알아야 한다.
  3. Int Index 값을 취하는 subscript를 통해서 컨테이너의 각 항목을 가져올 수 있어야 한다.

이를 준수하는 모든 타입은 저장하는 값의 타입을 명시해야 하고 이 값은 컨테이너에 추가될 수 있는 타입임을 보장해야만 한다. 이를 위해서 타입의 언급이 필요한데, 이때 사용하는 것이 associatedtype 이다.

추가로 associatedtype 에도 제약을 줄 수 있는데,

protocol Container {
    associatedtype Item : Equatable
}

이런 식으로 해당 프로토콜을 준수하는 타입만 올 수 있게 제약을 걸어주었다.

프로토콜은 자기 자신의 요구사항의 일부로 표현이 가능하다.

protocol SuffixableContainer: Container {
    associatedtype Suffix: SuffixableContainer where Suffix.Item == Item
    func suffix(_ size: Int) -> Suffix
}

이 프로토콜에서 Suffix는 알맞은 프로토콜은 준수해야 하고, Item은 컨테이너의 Item 타입과 같아야 한다.

내 생각에는 associatedtype은 제네릭과 거의 동일한 기능을 하지 않나 싶다. placeholder 역할도 수행하고, 제약도 줄 수 있기 때문이다. 두개의 차이에 대해서 알아볼 필요가 있을 듯 하다

06.15 추가 associatedtype은 구현에서 결정이 되고, 제네릭은 호출자가 선택한다는 차이가 있다. 배열의 경우, 제네릭 요소에서 어떤 구체적인 유형인지 선택이 가능하다. 이러한 차이를 생각하고 무엇을 쓸지 정하면 좋을 듯 하다.


참고

https://boidevelop.tistory.com/16

https://hyunsikwon.github.io/swift/Swift-AssociatedType/

profile
hi there 👋

0개의 댓글