2017-05-19 11 views
2

ジェネリック型のパラメータを持つクラスで指定されたinitを呼び出す便利なinitメソッドを作成する際に問題があります。ここでは、迅速3.1 XCodeのバージョン8.3.2(8E2002)遊び場迅速な利便性の初期化とジェネリッククラス

protocol A { 
    var items: [String] { get set } 
    func doSomething() 
} 

struct Section : A { 
    var items: [String] = [] 

    func doSomething() { 
     print("doSomething") 
     items.forEach { print($0) } 
    } 
} 

class DataSource<T: A> { 
    var sections: [T] 

    init(sections: [T]) { 
     self.sections = sections 
    } 

    func process() { 
     sections.forEach { $0.doSomething() } 
    } 

    convenience init() { 
     var section = Section() 
     section.items.append("Goodbye") 
     section.items.append("Swift") 

     self.init(sections: [section]) 
    } 
} 

/*: Client */ 
var section = Section() 
section.items.append("Hello") 
section.items.append("Swift") 

let ds = DataSource(sections: [section]) 
ds.process() 

はinitが存在していない便利な場合で、その下にあるコードは、/ *:クライアント* /セクションでは、コンパイルし、問題なく実行されます。私は便利なのinitに追加する場合、私は、次のコンパイルエラーを取得:

cannot convert value of type '[Section]' to expected argument type '[_]' 
     self.init(sections: [section]) 

私はコンビニエンスINITに私がプロトコルにどの満たすを実装セクションの構造体を作成していますので、これは問題になるだろうとは思いませんでしょうDataSourceクラスの汎用制約。コンビニエンスinitはクライアントコードと同じ操作を実行していますが、[Section]を[A]に変換することはできません。これは初期化シーケンスの問題ですか?

答えて

1

ジェネリックプレースホルダは、指定されたジェネリック型の使用で満たされている - ので、あなたのconvenience initの内側に、あなたTSectionであること仮定することはできません。それはAに従う任意の具体的なタイプです。例えば

呼び出し側が

struct SomeOtherSection : A {...} 

を定義し、TSomeOtherSectionことで便利に初期化子を呼び出すようにするために、それは完全に合法だろう。この場合の解決策は単純です

、あなただけTSectionであることに制約されているDataSourceの延長に便利に初期化子を追加することができます - ので[Section]
コールinit(sections:)にあなたを許可する:

extension DataSource where T == Section { 

    convenience init() { 
     var section = Section() 
     section.items.append("Goodbye") 
     section.items.append("Swift") 

     self.init(sections: [section]) 
    } 
} 

// ... 

// compiler will infer that T == Section here. 
let ds = DataSource() 
+0

素晴らしいありがとう! – user6902806

関連する問題