akuzminskyi
(Andrii Kuzminskyi)
1
Hi, I'm trying to create a generic solution for Validation. But stuck on a problem where I want to compound validators that validate the same type.
protocol Validator {
associatedtype ValidationType
func validate(_ value: ValidationType)
}
struct CompoundValidator<T, V: Validator>: Validator where V.ValidationType == T {
typealias ValidationType = T
private let validators: [V]
init(validators: [V]) {
self.validators = validators
}
func validate(_ value: ValidationType) {
for validator in validators {
validator.validate(value)
}
}
}
A sample how want to use
struct EmptyStringValidator: Validator {
typealias ValidationType = String
func validate(_ value: ValidationType) { }
}
struct LenghtValidator: Validator {
typealias ValidationType = String
func validate(_ value: ValidationType) { }
}
// works
let validator1= CompoundValidator(validators: [EmptyStringValidator(), EmptyStringValidator()])
validator1.validate("sample string")
// doesn't work "Cannot convert value of type 'EmptyStringValidator' to expected element type '_'"
let validator2 = CompoundValidator(validators: [EmptyStringValidator(), LenghtValidator()])
validator2.validate("sample string")
Can someone help me with it.
The way Generics work in Swift is each specialized version is, for this purpose, it's own unique Type. So, Array<SuperClass> is a different Type from Array<ChildClass> the same way Array<String> and Array<Int> are different.
So while the Type of validator1 can be CompoundValidator<EmptyStringValidator>, there's no reasonable Type for validator2 (since it has to a concrete type, i.e. not a protocol).
I believe there will be better options for this in the future, but one current workaround would be to re-organize the structure a bit.
protocol Validator {
associatedtype ValidationType
func validate(_ value: ValidationType)
}
struct GenericValidator<ValidationType>: Validator {
let validation: (ValidationType) -> ()
init(validation: @escaping (ValidationType) -> ()) {
self.validation = validation
}
func validate(_ value: ValidationType) { validation(value) }
}
struct CompoundValidator<ValidationType>: Validator {
let validators: [GenericValidator<ValidationType>]
init(validators: [GenericValidator<ValidationType>]) {
self.validators = validators
}
func validate(_ value: ValidationType) { validators.forEach{$0.validate(value)} }
}
let emptyStringValidator = GenericValidator<String>.init{ print(!$0.isEmpty) }
let lengthValidator = GenericValidator<String>.init{ print($0.count > 10) }
// works
let validator1 = CompoundValidator(validators: [emptyStringValidator, emptyStringValidator])
validator1.validate("sample string")
// doesn't work "Cannot convert value of type 'EmptyStringValidator' to expected element type '_'"
let validator2 = CompoundValidator(validators: [emptyStringValidator, lengthValidator])
validator2.validate("sample string")
akuzminskyi
(Andrii Kuzminskyi)
4
Thank you @GetSwifty . I think this solution should help me.