2016-11-04 6 views
0

私はフォーム入力ライブラリで作業しています。私の目標は、一連のフォームフィールドに適用できる再利用可能なバリデータセットを用意することです。私はジェネリックプロトコルを専門にするのが難しいです。以下のコードの完全なエラーはprotocol 'FieldValidator' can only be used as a generic constraint because it has Self or associated type requirementsです。"プロトコルXは一般的な制約としてのみ使用できます"

完全遊び場対応コード:

import Foundation 

protocol FieldValidator { 
    associatedtype InputType: Any 
    func validate(input value: InputType) 
} 

struct EmailValidator: FieldValidator { 
    func validate(input value: String) {} 
} 

enum Field { 
    case string(_: [FieldValidator]) 
    case integer(_: [FieldValidator]) 
} 

let emailField: Field = .string([EmailValidator()]) 

私は

を試してみた私はそれが何を知っておく必要があるためField列挙型で、私はちょうどFieldValidatorに投げることができないということを理解しますそれが必要とするバリデータのInputType

case string(_: [FieldValidator<String>]) 
case integer(_: [FieldValidator<Int>]) 

またはこの:

case string(_: [FieldValidator where InputType == String]) 
case integer(_: [FieldValidator where InputType == Int]) 

が、これらは動作しません。私はこのような何か多分、何とかそれを伝える必要があることを期待しています。このような建築を維持する方法はありますか? structの代わりに、フィールドタイプのためenumを使用して

編集:protocol 'FieldValidator' can only be used as a generic constraint because it has Self or associated type requirements

struct StringField { 
    typealias InputType = String 
    let validators: [FieldValidator] 
} 

私はまだ(フィールドが初期化されたときに提供する必要があります)バリデータのセットを定義する同じ問題を抱えているように見えます。

+1

は密な私を呼び出して、私は列挙型が_for_が何であるかを把握していませんよ。 – matt

+0

これは、使用可能なさまざまなタイプのフィールドを定義するために選択した方法です。また、フォームフィールドに渡され、フォームフィールドから取得される値のタイプを判別するためにも使用されます。これは一連の構造体である可能性があります。struct StringField、struct IntField。 – tobygriffin

+0

@matt私は、列挙型ではなく構造体またはクラスを使用していましたが、どちらのクラスでも運がありませんでした。より良い選択肢がありますか? – tobygriffin

答えて

1

I suppose what I'm trying to do is provide a mechanism by which someone can define a Field, define what type of value it holds, and define a set of reusable Validators which will operate on that value and determine if it's valid

次のような場合があります。それは問題では非常に多くのフィールドタイプが存在しない場合は特に、愚かだが効果的です:あなたが見ることができるように、私は単に私たちが持っていないように(問題を解決するためのクラス階層を使用しました

protocol FieldValidator { 
    associatedtype T 
    func validate(input:T) 
} 

class StringValidator : FieldValidator { 
    func validate(input:String) { fatalError("must override me") } 
} 

class IntValidator : FieldValidator { 
    func validate(input:Int) { fatalError("must override me") } 
} 

class ActualStringValidator : StringValidator { 
    override func validate(input:String) { print(input)} 
} 

enum Field { 
    case string([StringValidator]) 
    case int([IntValidator]) 
} 

タイプ消去を行う)。特に、言って、今の法律である:

let f = Field.string([ActualStringValidator()]) 

ここでそれをテストする方法は次のとおりです。

let f = Field.string([ActualStringValidator()]) 
if case Field.string(let arr) = f { 
    for thing in arr { 
     thing.validate(input:"howdy") 
    } 
} 
+0

ありがとう、これはうまく動作します。 'class'については恥ずかしいですが、少なくともそれは仕事をうまくやっています。 enumを 'case string([FieldValidator ])'として定義することが可能であることがわかりました。次に、 'ActualStringValidator'は' FieldValidator 'を仲介する必要なしに継承できます。 – tobygriffin

+0

確かに 'class'については残念ですが、構造体のアプローチが型の削除を必要とすることはかなり確かです。これは少し毛深いものです。あなたが望むなら、私はその解決策を試してみるつもりです(しかし私はむしろそうしたいと思います)。 – matt

+0

ハッピーではありません!ありがとうございました – tobygriffin

関連する問題