【发布时间】:2015-10-24 01:40:37
【问题描述】:
作为学习练习,我正在用 Swift 重写我的 validation library。
我有一个ValidationRule 协议,它定义了各个规则的外观:
protocol ValidationRule {
typealias InputType
func validateInput(input: InputType) -> Bool
//...
}
关联类型InputType 定义要验证的输入类型(例如字符串)。它可以是显式的或通用的。
这里有两条规则:
struct ValidationRuleLength: ValidationRule {
typealias InputType = String
//...
}
struct ValidationRuleCondition<T>: ValidationRule {
typealias InputType = T
// ...
}
在其他地方,我有一个函数可以使用 ValidationRules 的集合验证输入:
static func validate<R: ValidationRule>(input i: R.InputType, rules rs: [R]) -> ValidationResult {
let errors = rs.filter { !$0.validateInput(i) }.map { $0.failureMessage }
return errors.isEmpty ? .Valid : .Invalid(errors)
}
我认为这会起作用,但编译器不同意。
在以下示例中,即使输入是字符串,rule1 的 InputType 也是字符串,而 rule2s InputType 是字符串...
func testThatItCanEvaluateMultipleRules() {
let rule1 = ValidationRuleCondition<String>(failureMessage: "message1") { $0.characters.count > 0 }
let rule2 = ValidationRuleLength(min: 1, failureMessage: "message2")
let invalid = Validator.validate(input: "", rules: [rule1, rule2])
XCTAssertEqual(invalid, .Invalid(["message1", "message2"]))
}
...我收到了非常有用的错误消息:
_ 不能转换为 ValidationRuleLength
这很神秘,但表明类型应该完全相等?
所以我的问题是......我如何将所有符合具有关联类型的协议的不同类型附加到集合中?
不确定如何实现我正在尝试的目标,或者是否有可能?
编辑
这是没有上下文的:
protocol Foo {
typealias FooType
func doSomething(thing: FooType)
}
class Bar<T>: Foo {
typealias FooType = T
func doSomething(thing: T) {
print(thing)
}
}
class Baz: Foo {
typealias FooType = String
func doSomething(thing: String) {
print(thing)
}
}
func doSomethingWithFoos<F: Foo>(thing: [F]) {
print(thing)
}
let bar = Bar<String>()
let baz = Baz()
let foos: [Foo] = [bar, baz]
doSomethingWithFoos(foos)
我们得到:
Protocol Foo 只能用作通用约束,因为它具有 自身或关联的类型要求。
我明白这一点。我需要说的是:
doSomethingWithFoos<F: Foo where F.FooType == F.FooType>(thing: [F]) {
}
【问题讨论】:
-
你使用的是什么版本的 Swift?
-
我正在使用最新的 Swift 2
-
什么是验证结果?请提供足够的代码以便我重现。
-
好的,添加了一个通用的等价物
标签: ios swift generics protocols type-alias