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

Swift コンパイラはResultType、実装されたプロトコル メソッドの型シグネチャによって の型を推測します。たとえば、次の の宣言では、明示的な宣言がなくてもStringOutputItem、コンパイラは がタイプであることを認識しStringOutputItemます。ResultTypeString

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が保証されます。StringOutputItemOutputItem

関連付けられた型の型推論を説明するため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 = Stringすることにより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 に答える