我正試圖在Swift中實作一個通用驗證器。該驗證器只是執行一些驗證,即電子郵件驗證,并根據值是否有效回傳true或false。
protocol Validator {
associatedtype Value
func validate(_ value: Value) -> Bool: Value.
}
我也成功地實作了這些驗證器。正如你所看到的,associatedValue作業得非常順利。
struct EmailValidator。Validator {
func validate(_ value: String) -> Bool {
NSPredicate(format: "SELF MATCHES %@", "[A-Z0-9a-z._% -] @[A-Za-z0-9.-] . [A-Za-z]{2,}").evaluate(with: value)
}
}
struct RequiredValidator。Validator {
func validate(_ value: String) -> Bool {
!value.isEmpty
}
}
但是現在我想有一個復合驗證器,它不需要符合Validator,但是它確實需要接受任何Validator,其中associatedValue是相同的。下面我有一個例子。
let compoundValidator = CompoundValidator< String>(EmailValidator(), RequiredValidator()
然而,當我試圖實作這個想法時,我遇到了一些錯誤,如不能專門化非通用型別的'Validator'或不能將'Value'型別的值轉換為預期的引數型別'Validator.Value'或協議'Validator'只能作為一個通用約束,因為它有Self或相關型別要求,取決于我試圖實作什么。有什么方法可以讓我使用泛型實作這個復合驗證器嗎?
struct CompoundValidator< Value> {
let validators: [Validator<Value> ]
init(_ validators: Validator<Value>...) {
self.validators = validators
}
func validate(_ value。Value) -> Bool {
validators.reduce(into: true) { partialResult, validator in
partialResult = partialResult && validator.validate(value)
}
}
}
uj5u.com熱心網友回復:
讓我們從頭開始,Validator<Value>是無效的語法,即使Validator是一個具有關聯型別的協議。Swift 還不允許存在性容器(協議參考)來宣告通用約束,where子句是一個例外。
struct AnyValidator<Value> 。Validator {
private let _validate: (Value) ->Bool
init<V: Validator>(_ validator: V) where V.Value == Value {
_validate = validator.validate
}
func validate(_ value: Value) -> Bool {
_validate(value)
}
}
extension Validator {
func eraseToAnyValidator() -> AnyValidator< Value> {
AnyValidator(self)
}
}
,你需要這樣更新定義:
struct CompoundValidator< Value> {
let validators: [AnyValidator<Value>]
init(_ validators: AnyValidator<Value> ...) {
self.validators = validators
}
然而,上述實作要求所有呼叫者呼叫.eraseToAnyValidator():
let compoundValidator = CompoundValidator(EmailValidator)。 eraseToAnyValidator(), RequiredValidator().eraseToAnyValidator())
如果你想減少呼叫者的負擔,那么你就需要在被呼叫者方面做一些作業:
struct CompoundValidator<Value> {
let validators: [AnyValidator<Value>]
init<V。Validator>(_ v: V) where V.Value == Value {
驗證器 = [v.eraseToAnyValidator() ] 。
}
init<V1: Validator, V2: Validator>(_ v1: V1, _ v2: V2) where V1.Value == Value,V2。 Value == Value {
驗證器 = [v1.eraseToAnyValidator(), v2.eraseToAnyValidator()] 。
}
init<V1: Validator, V2: Validator, V3: Validator>(_ v1: V1, _ v2: V2, _ v3: V3) where V1.Value == Value,V2。 Value == Value, V3. Value == Value {
驗證器 = [v1.eraseToAnyValidator(), v2.eraseToAnyValidator(), v3.eraseToAnyValidator() ]
}
,基本上你需要添加多少個初始化器,就會有多少個你想通過代碼庫的引數。這使你能夠以簡單的形式呼叫初始化器:
let compoundValidator = CompoundValidator(EmailValidator)。RequiredValidator())
uj5u.com熱心網友回復:
struct CompoundValidator< Value, T: Validator> where T.Value ==Value {
let validators: [T]
init(_ validators: T...) {
self.validators = validators
}
func validate(_ value。Value) -> Bool {
validators.reduce(into: true) { partialResult, validator in
partialResult = partialResult && validator.validate(value)
}
}
}
uj5u.com熱心網友回復:
你可以創建一個AnyValidator型別,它是一個具體的型別。這樣你就可以用它來指定通用型別的引數。
struct AnyValidator<Value> 。Validator {
private let validateFunc: (Value) ->Bool
init<T: Validator>(_ validator: T) where T.Value == Value {
validateFunc = validator.validate
}
func validate(_ value: Value) -> Bool {
validateFunc(value)
}
}
extension Validator {
func eraseToAnyValidator() -> AnyValidator< Value> {
.init(self)
}
}
struct CompoundValidator<Value> {
let validators: [AnyValidator<Value>]
init(_ validators: AnyValidator<Value> ...) {
self.validators = validators
}
func validate(_ value。Value) -> Bool {
validators.reduce(into: true) { partialResult, validator in
partialResult = partialResult && validator.validate(value)
}
}
}
示例用法:
CompoundValidator(
EmailValidator().eraseToAnyValidator()。
RequiredValidator().eraseToAnyValidator())
你可能想為少數驗證器提供方便的初始化器:
init< V1, V2>(_ v1: V1, _ v2: V2) where V1: Validator, V2: Validator, V1.Value == Value, V2。 Value == Value {
self.init(v1.eraseToAnyValidator(), v2.eraseToAnyValidator() )
}
init<V1, V2, V3> (_ v1: V1, _ v2: V2, _ v3: V3) where V1: Validator, V2: Validator, V3: Validator, V1.Value == Value, V2。 Value == Value, V3. Value == Value {
self.init(v1.eraseToAnyValidator(), v2.eraseToAnyValidator(), v3.eraseToAnyValidator()
}
這允許你省略.eraseToAnyValidator()。
這類似于Combine的Publisher型別有一個merge運算子,它最多接受8個引數,只是為了允許你合并不同型別的Publisher,而不用說eraseToAnyPublisher。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/333015.html
標籤:
