programing

Swift에서 프로토콜의 관련 유형이 일반 유형 구문을 사용하지 않는 이유는 무엇입니까?

newsource 2023. 8. 28. 21:03

Swift에서 프로토콜의 관련 유형이 일반 유형 구문을 사용하지 않는 이유는 무엇입니까?

저는 프로토콜의 관련 유형에 사용되는 구문과 일반 유형의 차이에 대해 혼란스럽습니다.

예를 들어 Swift에서는 다음과 같은 것을 사용하여 제네릭 유형을 정의할 수 있습니다.

struct Stack<T> {
    var items = [T]()
    mutating func push(item: T) {
        items.append(item)
    }
    mutating func pop() -> T {
        return items.removeLast()
    }
}

같은 것을 사용하여 연관된 유형의 프로토콜을 정의하는 동안.

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

왜 후자는 그냥 그렇지 않습니까?

protocol Container<T> {
    mutating func append(item: T)
    var count: Int { get }
    subscript(i: Int) -> T { get }
}

언어가 후자의 구문을 채택하지 않은 깊은 이유가 있습니까?

롭 네이피어의 대답은 (평소와 다름없이) 꽤 괜찮지만, 다른 관점에서 보면 좀 더 도움이 될 것 같습니다.

연관된 유형

프로토콜은 추상적인 요구사항 집합으로, 특정 유형이 프로토콜을 준수한다고 말하기 위해 충족해야 하는 체크리스트입니다.전통적으로 사람들은 행동에 대한 체크리스트를 생각합니다: 구체적인 유형에 의해 구현된 방법이나 특성.연관된 유형은 이러한 체크리스트와 관련된 항목의 이름을 지정하여 적합한 유형이 적합성을 구현하는 방법에 대해 열린 상태로 유지하면서 정의를 확장하는 방법입니다.

표시되는 경우:

protocol SimpleSetType {
    associatedtype Element
    func insert(_ element: Element)
    func contains(_ element: Element) -> Bool
    // ...
}

이 그이의 미는것은하에 , 유이적고주것는입장다니하다합하형것▁to▁what▁conform다ance것입,▁to니▁type▁claim▁that,.SimpleSetType에는 해당유형다포합함니야다해을음은합▁contain▁that▁must다니▁only를 포함해야 합니다.insert(_:)그리고.contains(_:)함수, 이 두 함수는 서로 동일한 유형의 매개 변수를 사용해야 합니다.그러나 매개 변수의 유형은 중요하지 않습니다.

일반 또는 비일반 유형으로 이 프로토콜을 구현할 수 있습니다.

class BagOfBytes: SimpleSetType {
    func insert(_ byte: UInt8) { /*...*/ }
    func contains(_ byte: UInt8) -> Bool { /*...*/ }
}

struct SetOfEquatables<T: Equatable>: SimpleSetType {
    func insert(_ item: T) { /*...*/ }
    func contains(_ item: T) -> Bool { /*...*/ }
}    

어느 곳에서도 할 수 없다는 것을 주목하세요.BagOfBytes또는SetOfEquatables사이의 연관성을 정의합니다.SimpleSetType.Element그리고 두 가지 방법에 대한 매개 변수로 사용되는 유형입니다. 컴파일러는 해당 유형이 올바른 방법과 연결되어 있으므로 연결된 유형에 대한 프로토콜의 요구 사항을 충족합니다.

일반 유형 매개변수에 대하여

연관된 유형이 추상 검사 목록을 만들기 위해 어휘를 확장하는 경우 일반 유형 매개 변수는 특정 유형의 구현을 제한합니다.다음과 같은 일반 클래스가 있는 경우:

class ViewController<V: View> {
    var view: V
}

그것은 그것을 만드는 많은 다른 방법들이 있다고 말하지 않습니다.ViewController▁a당▁(▁as)가 있는 한.view), a로 표시됩니다.ViewController 현실적이고 구체적인 것이고, 그것은 그것을 가지고 있습니다.view더 , 우리는 어떤 있는지 못합니다.ViewController인스턴스는 그랬지만, 우리는 그것이 분명하다는 것을 알고 있습니다.View의입니다.Viewclass, 또는그구것유현형는하을을 입니다.View말하지 우리는 말하지 않습니다).

즉, 일반적인 유형이나 함수를 작성하는 것은 실제 코드를 작성하는 일종의 지름길입니다.다음 예를 들어 보겠습니다.

func allEqual<T: Equatable>(a: T, b: T, c: T) {
    return a == b && b == c
}

이것은 마치 당신이 모든 것을 겪은 것과 같은 효과를 가집니다.Equatable유형 및 기록:

func allEqual(a: Int, b: Int, c: Int) { return a == b && b == c }
func allEqual(a: String, b: String, c: String) { return a == b && b == c }
func allEqual(a: Samophlange, b: Samophlange, c: Samophlange) { return a == b && b == c }

보다시피, 우리는 여기서 코드를 만들고 새로운 동작을 구현하고 있습니다. 이는 다른 요구사항만 설명하는 프로토콜 관련 유형과는 매우 다릅니다.

TLDR

관련 유형과 일반 유형 매개 변수는 매우 다른 종류의 도구입니다. 관련 유형은 설명 언어이고 일반 유형은 구현 언어입니다.사용 용도가 가끔 비슷해 보이지만(특히 모든 요소 유형의 컬렉션에 대한 추상적인 Blueprint와 여전히 모든 일반 요소를 포함할 수 있는 실제 컬렉션 유형 간의 미묘한 차이가 있는 경우) 매우 다른 목적을 가지고 있습니다.그들은 매우 다른 동물이기 때문에, 구문이 다릅니다.

진일보한 내용

Swift 팀은 제네릭, 프로토콜 및 관련 기능에 대해 잘 알고 있습니다.

이것은 개발자 목록에서 몇 번 다뤄졌습니다.기본적인 답변은 관련 유형이 유형 매개 변수보다 유연하다는 것입니다.여기에는 한 가지 유형 매개 변수의 특정 사례가 있지만 여러 가지 경우가 있을 수 있습니다.예를 들어 컬렉션에는 요소 유형뿐만 아니라 인덱스 유형과 생성기 유형도 있습니다.만약 당신이 그것들을 완전히 유형 매개변수화로 전문화했다면, 당신은 다음과 같은 것들에 대해 이야기해야 할 것입니다.Array<String, Int, Generator<String>>뭐그것들런될 수 있는 의 다른 많은 할 수 있습니다이를 통해 Int 이외의 기능으로 간주될 수 있는 다른 기능에 의해 서브스크립션된 어레이를 만들 수 있을 뿐만 아니라 많은 복잡성도 추가할 수 있습니다.

이 모든 것을 생략할 수 있지만(Java는 생략) 유형을 제한할 수 있는 방법이 더 적습니다.사실 자바는 유형을 제한할 수 있는 방법이 상당히 제한적입니다.Java 컬렉션에는 임의 인덱싱 유형을 사용할 수 없습니다.Scala는 Swift와 마찬가지로 Java 유형 시스템을 관련 유형으로 확장합니다.관련 유형은 Scala에서 믿을 수 없을 정도로 강력했습니다.그들은 또한 정기적으로 혼란과 머리카락을 찢는 원인이 되기도 합니다.

이 추가적인 힘이 그것의 가치가 있는지 여부는 완전히 다른 질문이며, 오직 시간이 말해줄 것입니다.그러나 관련 유형은 단순한 유형 매개변수화보다 확실히 더 강력합니다.

이미 훌륭한 답변에 덧붙여, 제네릭과 관련 유형 사이에는 또 다른 큰 차이가 있습니다. 즉, 유형 일반 이행의 방향입니다.

제네릭 형식의 경우 제네릭에 사용할 형식을 지정하는 것은 클라이언트이며, 관련 형식이 있는 프로토콜의 경우 유형 자체를 완전히 제어할 수 있습니다.즉, 관련 유형을 준수하는 유형은 자신이 모르는 유형과 함께 작업하도록 강요받는 대신 자신에게 가장 적합한 유형을 선택할 수 있습니다.

다른 사람들이 말했듯이,Collection프로토콜은 어떤 경우에 관련 유형이 더 적합한 이유를 보여주는 좋은 예입니다.프로토콜은 다음과 같습니다(다른 관련 유형 중 일부를 생략했습니다).

protocol Collection {
    associatedtype Element
    associatedtype Index

    ...
}

프로토콜이 다음과 같이 정의되었더라면Collection<Element, Index>그러면 이것은 적합한 유형에 큰 부담을 줄 것입니다.Collection모든 종류의 인덱싱을 지원해야 하기 때문에, 그 중 많은 것들은 말도 안 되는 것들입니다(예: 에 의한 인덱싱).UIApplication값).

따라서, 프로토콜 제네릭에 대한 관련 유형을 선택하는 것은 또한 해당 프로토콜에 부합하는 유형에 권한을 부여하는 문제이기도 합니다. 제네릭에서 발생하는 작업을 지시하는 유형이기 때문입니다.그리고 네, 유연성이 떨어지는 것처럼 들릴 수도 있지만, 생각해보면 다음과 같은 모든 유형이 있습니다.Collection제릭형만즉해유에당형지이식, 유형다니허제합용대을네해릭만서해당네즉에▁that▁are다,ics▁allow▁fori▁gener허니▁types▁types▁only합)에 만 제네릭을 허용합니다.Element), 유형 "은 "하드코딩하드코딩")입니다Index를 사용하여 할 수 합니다. 컨텍스트에서 사용할 수 있는 유형입니다.

언급URL : https://stackoverflow.com/questions/26554987/why-dont-associated-types-for-protocols-use-generic-type-syntax-in-swift