难以理解Swift协议扩展中的“关联类型”

难以理解Swift协议扩展中的“关联类型”,swift,swift-extensions,swift-protocols,Swift,Swift Extensions,Swift Protocols,我正在努力理解swift中的协议和协议扩展 我想定义一系列可应用于类的协议,以及一组提供默认实现的协议扩展。示例代码: // MARK: - Protocols & Protocol Extensions protocol OutputItem { typealias ResultType func rawValue() -> ResultType // other requirements ... } protocol StringOutputItem

我正在努力理解swift中的协议和协议扩展

我想定义一系列可应用于类的协议,以及一组提供默认实现的协议扩展。示例代码:

// MARK: - Protocols & Protocol Extensions
protocol OutputItem {
    typealias ResultType
    func rawValue() -> ResultType
    // other requirements ...
}

protocol StringOutputItem : OutputItem {}
extension StringOutputItem {
    typealias ResultType = String
    override func rawValue() -> Self.ResultType {
        return "string ouput"
    }
}

protocol IntOutputItem: OutputItem {}
extension IntOutputItem {
    typealias ResultType = Int
    override func rawValue() -> Self.ResultType {
        return 123
    }
}
扩展中的
rawValue()
的上述重写函数在'Self'中给出了一个不明确的类型名'ResultType'。如果我从
Self.ResultType
中删除
Self
,我会得到一个错误
“ResultType”对于此上下文中的类型查找是不明确的

如何向协议扩展发送用于
ResultType
的类型的信号

我的目标是能够将协议及其扩展应用于一个类,如下所示:

// MARK: - Base Class
class DataItem {
    // Some base class methods
    func randomMethod() -> String {
        return "some random base class method"
    }
}

// MARK: - Subclasses
class StringItem : DataItem, StringOutputItem {
    // Some subclass methods
}

class AnotherStringItem : DataItem, StringOutputItem {
    // Some subclass methods
}

class IntItem : DataItem, IntOutputItem {
    // Some subclass methods
}
以便:

let item1 = StringItem()
print(item1.rawValue())         // should give "string output"

let item2 = AnotherStringItem()
print(item2.rawValue())         // should give "string output"

let item3 = IntItem()
print(item3.rawValue())         // should give 123

如果我完全不了解协议扩展如何提供默认实现,我对如何实现相同的结果持开放态度。

Swift编译器通过实现的协议方法的类型签名推断出
ResultType
的类型。例如,在下面的
StringOutputItem
声明中,编译器知道
StringOutputItem
ResultType
String
类型,即使没有显式声明:

protocol StringOutputItem: OutputItem {}

extension StringOutputItem {
    func rawValue() -> String {
        return "string output"
    }
}

class StringItem : DataItem, StringOutputItem {}

let item = StringItem()
print(item.rawValue()) // prints "string output"
我们可以在
StringOutputItem
中显式声明
ResultType
,这将确保
StringOutputItem
符合
OutputItem
协议,并使用正确的类型实现它

为了说明关联类型的类型推断,假设
OutputItem
指定另一个方法作为其协议的一部分。如果我们提供类型不匹配的默认实现,编译器将抛出一个错误,指示实现类型不符合协议

protocol OutputItem {
    typealias ResultType
    func rawValue() -> ResultType
    func printValue(r: ResultType)
}

protocol StringOutputItem: OutputItem {}

extension StringOutputItem {
    func rawValue() -> String {
        return "string output"
    }
    func printValue(r: Int) {  // Should be String
        ...
    }
}

struct Test: StringOutputItem {} // Error: Type 'Test' does not conform to protocol 'OutputItem'
通过在
StringOutputItem
中显式声明
typealias ResultType=String
,我们可以确保在实现协议的方法时使用正确的类型

protocol OutputItem {
    typealias ResultType
    func rawValue() -> ResultType
    func printValue(r: ResultType)
}

protocol StringOutputItem: OutputItem {}

extension StringOutputItem {
    typealias ResultType = String // without this typealias declaration, the program WILL compile since ResultType is inferred to be of type Int
    func rawValue() -> Int {
        return 123
    }
    func printValue(r: Int) {  
        ...
    }
}

struct Test: StringOutputItem {} // Error: Type 'Test' does not conform to protocol 'OutputItem'

Swift编译器通过实现的协议方法的类型签名推断出
ResultType
的类型。例如,在下面的
StringOutputItem
声明中,编译器知道
StringOutputItem
ResultType
String
类型,即使没有显式声明:

protocol StringOutputItem: OutputItem {}

extension StringOutputItem {
    func rawValue() -> String {
        return "string output"
    }
}

class StringItem : DataItem, StringOutputItem {}

let item = StringItem()
print(item.rawValue()) // prints "string output"
我们可以在
StringOutputItem
中显式声明
ResultType
,这将确保
StringOutputItem
符合
OutputItem
协议,并使用正确的类型实现它

为了说明关联类型的类型推断,假设
OutputItem
指定另一个方法作为其协议的一部分。如果我们提供类型不匹配的默认实现,编译器将抛出一个错误,指示实现类型不符合协议

protocol OutputItem {
    typealias ResultType
    func rawValue() -> ResultType
    func printValue(r: ResultType)
}

protocol StringOutputItem: OutputItem {}

extension StringOutputItem {
    func rawValue() -> String {
        return "string output"
    }
    func printValue(r: Int) {  // Should be String
        ...
    }
}

struct Test: StringOutputItem {} // Error: Type 'Test' does not conform to protocol 'OutputItem'
通过在
StringOutputItem
中显式声明
typealias ResultType=String
,我们可以确保在实现协议的方法时使用正确的类型

protocol OutputItem {
    typealias ResultType
    func rawValue() -> ResultType
    func printValue(r: ResultType)
}

protocol StringOutputItem: OutputItem {}

extension StringOutputItem {
    typealias ResultType = String // without this typealias declaration, the program WILL compile since ResultType is inferred to be of type Int
    func rawValue() -> Int {
        return 123
    }
    func printValue(r: Int) {  
        ...
    }
}

struct Test: StringOutputItem {} // Error: Type 'Test' does not conform to protocol 'OutputItem'