首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >什么时候在Swift中使用类型擦除?

什么时候在Swift中使用类型擦除?
EN

Stack Overflow用户
提问于 2021-04-30 16:52:58
回答 1查看 407关注 0票数 1

关于如何在Swift中执行类型擦除,已经有很多问题,我看到类型擦除常常被描述为处理具有关联类型和泛型类型的协议的一种重要模式。

然而,在我看来,需要类型擦除通常是设计问题的症状--您本质上是在“丢弃”类型信息(即将值放入容器或将其传递给函数),这些信息最终通常需要通过冗长而易碎的向下转换来恢复。也许我不明白的是像AnyHashable这样的“类型”的用例--带有self的PATs/协议只能用作泛型约束,因为它们没有具体化类型,这让我想知道有什么令人信服的理由想要将它们具体化。

简而言之,在Swift中使用类型擦除是的好想法吗?我正在寻找一些关于何时使用此模式的一般指导方针,以及一些实际用例的示例,其中类型擦除优于其替代方法。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-04-30 19:24:21

我试图找到一个极简的类型擦除的例子。根据我的经验,它往往变得更加复杂,我尽量避免它。但有时候就是这样。

它终于和以前一样复杂了,有了古老的语言。除了旧式的语言是通过崩溃伤害你,而快速伤害你在建筑时间。

它是一种强类型语言,因此它不适合泛型语言。

假设您需要管理文档中的一些形状。这些形状是Identifiables,这意味着它们有一个由关联类型决定的id。在这种情况下。

下面的代码不会生成,因为它不能直接使用Shape协议,因为id类型是由符合形状协议的对象定义的关联类型

代码语言:javascript
复制
import Foundation

protocol Shape: AnyShape, Identifiable {
    var name: String { get }
}

struct Square: Shape {
    var id: Int = 0
    var name: String { "Square" }
}

func selectShape(_ shape: Shape) {
    print("\(shape.name) selected")
}

通过添加类型擦除的形状,然后可以将其传递给函数。因此,这将建立:

代码语言:javascript
复制
import Foundation

protocol AnyShape {
    var name: String { get }
}

protocol Shape: AnyShape, Identifiable {
    
}

struct Square: Shape {
    var id: Int = 0
    var name: String { "Square" }
}

func selectShape(_ shape: AnyShape) {
    print("\(shape.name) selected")
}

简单用例.

假设现在我们的应用程序连接到两个形状的制造商服务器,以获取它们的目录并与我们的服务器同步。

我们知道世界各地的形状都是形状,但是数据库中的ACME形状工厂索引是Int,而Shapers俱乐部使用UUID

在这一点上,我们需要‘恢复’的类型,正如你说的。这正是在查看AnyHashable源代码文档时所解释的。

Cast是无法避免的,它最终对应用程序的安全性和模型的可靠性都是一件好事。

第一部分是协议,它可能是冗长的,随着情况的增加而变得复杂,但它将是应用程序的通信基础框架,不应该经常改变。

代码语言:javascript
复制
import Foundation

// MARK: - Protocols

protocol AnyShape {
    var baseID: Any { get }
    var name: String { get }
}

// Common functions to all shapes

extension AnyShape {
    
    func sameObject(as shape: AnyShape) -> Bool {
        switch shape.baseID.self {
        case is Int:
            guard let l = baseID as? UUID , let r = shape.baseID as? UUID else { return false }
            return l == r
        case is UUID:
            guard let l = baseID as? UUID , let r = shape.baseID as? UUID else { return false }
            return l == r
        default:
            return false
        }
    }

    func sameShape(as shape: AnyShape) -> Bool {
        return name == shape.name
    }

    func selectShape(_ shape: AnyShape) {
        print("\(shape.name) selected")
    }
}

protocol Shape: AnyShape, Identifiable {
    
}

extension Shape {
    var baseID: Any { id }
}

第二部分是模型-这将有望随着我们与更多的形状制造商的工作而发展。

可以对形状执行的敏感操作不在此代码中。因此,创建和调整模型和apis没有问题。

代码语言:javascript
复制
// MARK: - Models

struct ACME_ShapeFactory_Model {
    struct Square: Shape {
        var id: Int = 0
        var name: String { "Square" }

        var ACME_Special_Feature: Bool
    }
}

struct ShapersClub_Model {
    struct Square: Shape {
        var id: UUID = UUID()
        var name: String { "Square" }

        var promoCode: String
    }
}

测试

代码语言:javascript
复制
let shape1: AnyShape = ACME_ShapeFactory_Model.Square()
let shape2: AnyShape = ShapersClub_Model.Square()
let shape3: AnyShape = ShapersClub_Model.Square()

Compare two different shapes references from different manufacturers

shape1.sameObject(as: shape2) : false
-> Logic, it can't be the same item if it comes from different manufacturers

Compare two different shapes references from same manufacturers

shape2.sameObject(as: shape3) : false
-> This is a new shape, sync in catalog

Compare two identical shapes references from same manufacturers 

shape2.sameObject(as: shape2) : true
-> We already have this one in the catalog

Compare two shapes from different manufacturers

shape1.sameShape(as: shape2) : true
-> Dear customer, we have two kind of squares from two manufacturers

就这样。我希望这会有什么帮助。欢迎任何更正或评论。

最后,我对我的形状制造商的名字感到非常自豪:)

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67337673

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档