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 我更喜欢使用单独的 StringConvertableIntConvertable 协议以及符合扩展的所需类型。 还有为什么需要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的类型擦除只是一个类型高低阶转换的游戏。

Swift之深入解析基于闭包的类型擦除

Type Erasure with Pokemon---swift的类型擦除

swift中的"类型擦除"

我们可以在 Swift 中创建具有非可选属性的类型擦除弱引用吗?

在Scala中对列表/序列进行模式匹配时解决类型擦除问题