约束关联类型
Constrain an associated type
显示问题的我的代码的简化版本:
protocol Transformer {
typealias Input
typealias Output
func transform(s: Input) -> Output
}
protocol InputType {}
protocol OutputType {}
extension Int: OutputType {}
extension String: InputType {}
struct StringToInt: Transformer {
typealias Input = String
typealias Output = Int
func transform(s: Input) -> Output {
return s.characters.count
}
}
typealias Transform = InputType -> OutputType
func convert<T: Transformer where T.Input == InputType, T.Output == OutputType>
(transformer: T) -> Transform {
return transformer.transform
}
convert(StringToInt()) // error: Cannot invoke 'convert' with an argument list of type '(StringToInt)'
我猜测错误的发生是因为编译器无法进入 StringToInt
并验证 Input
和 Output
确实符合 InputType
和 OutputType
分别。
对我来说,解决这个问题的最好方法是直接在协议中约束关联类型。它将更具表现力,编译器将获得更多信息。但是简单地做 typealias Input: InputType
是行不通的。
有什么方法可以约束关联类型吗?
您可以为 Transformer
协议创建扩展
extension Transformer where Input: InputType, Output: OutputType {
func convert() -> Input -> Output {
return transform
}
}
现在您可以在 StringToInt
个实例上调用 convert
方法。
StringToInt().convert()
但是对于其他没有Input
和Output
的类型采用InputType
和OutputType
它不会编译
struct DoubleToFloat: Transformer {
func transform(s: Double) -> Float {
return Float(s)
}
}
DoubleToFloat().convert() // compiler error
摆脱 Transform
别名用法,为输入和输出类型添加泛型并将它们映射到 Transformer
,您将获得 StringToInt
的工作代码对于您编写的其他转换器:
func convert<T: Transformer, I, O where T.Input == I, T.Output == O>
(transformer: T) -> I -> O {
return transformer.transform
}
convert(StringToInt())
顺便说一句,您不需要为 StringToInt
指定类型别名,如果您指定实际类型,编译器能够从函数定义中推断出这些别名:
struct StringToInt: Transformer {
func transform(s: String) -> Int {
return s.characters.count
}
}
显示问题的我的代码的简化版本:
protocol Transformer {
typealias Input
typealias Output
func transform(s: Input) -> Output
}
protocol InputType {}
protocol OutputType {}
extension Int: OutputType {}
extension String: InputType {}
struct StringToInt: Transformer {
typealias Input = String
typealias Output = Int
func transform(s: Input) -> Output {
return s.characters.count
}
}
typealias Transform = InputType -> OutputType
func convert<T: Transformer where T.Input == InputType, T.Output == OutputType>
(transformer: T) -> Transform {
return transformer.transform
}
convert(StringToInt()) // error: Cannot invoke 'convert' with an argument list of type '(StringToInt)'
我猜测错误的发生是因为编译器无法进入 StringToInt
并验证 Input
和 Output
确实符合 InputType
和 OutputType
分别。
对我来说,解决这个问题的最好方法是直接在协议中约束关联类型。它将更具表现力,编译器将获得更多信息。但是简单地做 typealias Input: InputType
是行不通的。
有什么方法可以约束关联类型吗?
您可以为 Transformer
协议创建扩展
extension Transformer where Input: InputType, Output: OutputType {
func convert() -> Input -> Output {
return transform
}
}
现在您可以在 StringToInt
个实例上调用 convert
方法。
StringToInt().convert()
但是对于其他没有Input
和Output
的类型采用InputType
和OutputType
它不会编译
struct DoubleToFloat: Transformer {
func transform(s: Double) -> Float {
return Float(s)
}
}
DoubleToFloat().convert() // compiler error
摆脱 Transform
别名用法,为输入和输出类型添加泛型并将它们映射到 Transformer
,您将获得 StringToInt
的工作代码对于您编写的其他转换器:
func convert<T: Transformer, I, O where T.Input == I, T.Output == O>
(transformer: T) -> I -> O {
return transformer.transform
}
convert(StringToInt())
顺便说一句,您不需要为 StringToInt
指定类型别名,如果您指定实际类型,编译器能够从函数定义中推断出这些别名:
struct StringToInt: Transformer {
func transform(s: String) -> Int {
return s.characters.count
}
}