2016-11-04 60 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爲字段類型:

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

我仍然看起來具有定義所述一組驗證器(當字段被初始化必須提供)同樣的問題:protocol 'FieldValidator' can only be used as a generic constraint because it has Self or associated type requirements

+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

謝謝,這工作得很好。對「班」感到羞恥,但至少它很好地完成了這項工作。我發現可以將枚舉定義爲'case string([FieldValidator ])',然後'ActualStringValidator'可以繼承'FieldValidator '而不需要中介。 – tobygriffin

+0

對於'class'肯定是一種恥辱,但我相當肯定struct結構的方法需要類型擦除,這有點多毛。如果你願意,我會盡力解決這個問題(但我寧願不)。 – matt

+0

快樂不要!謝謝 – tobygriffin