Swift 类型擦除 - 对于这种情况?
Posted
技术标签:
【中文标题】Swift 类型擦除 - 对于这种情况?【英文标题】:Swift type erasure - for this case? 【发布时间】:2018-04-13 19:53:49 【问题描述】:我需要实现 TypeConverter 并稍后将其用作变量类型。受 ObjectMapper 的启发,我定义了以下协议:
protocol TypeConverter
associatedtype A
associatedtype B
func transformFrom(fromType: A?) -> B?
func transformTo(toType: B?) -> A?
具体实现是:
class IntToStringTypeConverter: TypeConverter
typealias A = Int
typealias B = String
func transformFrom(fromType: Int?) -> String?
guard let fromType = fromType else return nil
return String(fromType)
func transformTo(toType: String?) -> Int?
guard let toType = toType else return nil
return Int(toType)
由于协议TypeConverter有关联类型,我不能将它声明为变量,例如:var转换器:TypeConverter,但我需要这样的功能。这种情况的解决方案是使用 typeErasure。通过这个链接https://medium.com/@NilStack/swift-world-type-erasure-5b720bc0318a 应该是可能的,但我不知道如何。
这是我的尝试,但它不正确:)...这甚至可以通过这种方式解决吗?或者我应该使用这个:https://appventure.me/2017/12/10/patterns-for-working-with-associated-types?
class AnyTypeConverter<Y, Z>: TypeConverter
typealias A = Y
typealias B = Z
private let _transformFrom: (Z?) -> Y?
private let _transformTo: (Y?) -> Z?
init<W: TypeConverter>(_ iFormTypeConverter: W) where W.A == Y, W.B == Z
self._transformFrom = iFormTypeConverter.transformFrom
self._transformTo = iFormTypeConverter.transformTo
func transformFrom(modelType: Y?) -> Z?
return transformFrom(modelType: modelType)
func transformTo(iFormType: Z?) -> Y?
return transformTo(iFormType: iFormType)
【问题讨论】:
用例是什么? FWIW 我更喜欢使用单独的StringConvertable
和 IntConvertable
协议以及符合扩展的所需类型。
还有为什么需要TypeConverter
对象。你应该可以声明var converter: IntToStringConverter
@gadu 感谢您的回复。请参阅下面的评论...
【参考方案1】:
对于具有关联类型的协议,这并不是一个很好的用途。 PAT 是非常复杂的工具,在这种情况下根本没有理由这样做。你甚至不需要一个类型橡皮擦,只需要一个结构:
struct TypeConverter<Model, Form>
let transformFrom: (Model) -> Form?
let transformTo: (Form) -> Model?
let stringToInt = TypeConverter(transformFrom:String.init,
transformTo:Int.init)
stringToInt.transformFrom(123)
stringToInt.transformTo("x")
如果你愿意,你当然可以使它符合TypeConverter
(我可以更新以添加它),但我建议完全放弃协议而只使用结构。这与Formatter
的工作方式非常接近。
【讨论】:
我知道格式化程序是如何工作的 - 你不会相信,但我开始的方式与你非常相似,但不知何故它不符合我的要求。 我知道格式化程序是如何工作的 - 你不会相信,但我开始的方式与你非常相似,但不知何故它不符合我的要求。我正在研究 FormRowDescription 对象,它可能有转换器来映射 DataModel 和 CellType 之间的数据类型 - 所以它可能是 String/Int、Float/Int - 任何东西:)。所以我需要让它通用。对象 FormRowDescription 当然应该适用于所有情况。这就是为什么我对我如此重要,可以选择将其声明为 var 转换器:ConverterType... 它不会进行类型擦除,它仍然可以选择将转换器声明为 Any, Any.... protocol AnyConverter // 非常丑陋的解决方案 func fromModel(value: Any?) -> Any? func toModel(value: Any?) -> Any? 类 IntoStringAnyConverter: AnyConverter func fromModel(value: Any?) -> Any? 守卫让价值=价值? Int else return nil return String(value) func toModel(value: Any?) -> Any? 守卫让价值=价值?字符串 else return nil return Int(value) class Test var anyConverter: AnyConverter init(anyConverter: AnyConverter) self.anyConverter = anyConverter let converter = IntoStringAnyConverter() let test = Test(anyConverter: converter) 上面的例子适合我的需要,但它太丑了。这就是为什么我试图以更奇特的方式解决它..当然如果可能的话【参考方案2】:在实现了两个单元之后,我发现我可以稍微简化一下这件事,并且只使用一个关联类型:)。单元格中使用的类型实际上是由 UI 组件定义的——如果有 UITextField,那么 type 将是 String,如果我实现自定义 stepper,它将是 Int(例如)。如果我想让我的单元格通用,那么它应该适用于任何类型,我可以为此编写模型和(预)定义的单元格类型之间的转换器。
protocol FormTypeConverter
associatedtype FormType
func fromModelToForm(_ value: Any?) -> FormType?
func fromFormToModel(_ value: FormType?) -> Any?
这样我可以使用如下简单的类型擦除(来源在第一篇文章的链接中)
struct AnyFormTypeConverter<T>: FormTypeConverter
// MARK: - Variables
private let fromModelToFormWrapper: (Any?) -> T?
private let fromFormToModelWrapper: (T?) -> Any?
init<Y: FormTypeConverter>(_ formTypeConverter: Y) where Y.FormType == T
self.fromModelToFormWrapper = formTypeConverter.fromModelToForm
self.fromFormToModelWrapper = formTypeConverter.fromFormToModel
func fromModelToForm(_ value: Any?) -> T?
return fromModelToFormWrapper(value)
func fromFormToModel(_ value: T?) -> Any?
return fromFormToModel(value)
这个案例实现非常适合。已经很快实现了两种完全不同的形式:)
【讨论】:
以上是关于Swift 类型擦除 - 对于这种情况?的主要内容,如果未能解决你的问题,请参考以下文章
swift类型擦除的定义-swift的类型擦除只是一个类型高低阶转换的游戏。
Type Erasure with Pokemon---swift的类型擦除