1

我正在努力快速理解协议和协议扩展。

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

// 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()给出了错误Ambiguous type name 'ResultType' in 'Self'。如果我Self从 中删除,Self.ResultType我会收到错误消息'ResultType' is ambiguous for type lookup in this context

如何向协议扩展发出信号,使用哪种类型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

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

4

1 回答 1

0

ResultTypeSwift 编译器通过实现的协议方法的类型签名来推断类型。例如,在以下 的声明中StringOutputItem,编译器知道StringOutputItem'sResultType的类型是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"

我们可以显式声明ResultTypein StringOutputItem,这将确保它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'

通过显式声明typealias ResultType = Stringin StringOutputItem,我们确保在实现协议的方法时使用正确的类型。

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'
于 2015-10-11T07:31:47.420 回答