我试图找到一个简单的类型擦除示例。根据我的经验,它通常会变得更复杂,我会尽量避免它。但有时就是这样。
终于和以前一样复杂了,用的是老式的语言。除了旧式语言会因崩溃而伤害您,而 swift 在构建时会伤害您。
它是一种强类型语言,所以它不适合泛型。
假设您需要管理文档中的一些形状。
这些形状是Identifiables,这意味着它们有一个id,其类型由关联的类型确定。在这种情况下为 Int。
下面的代码不会编译,因为它不能直接使用Shape 协议,因为id 的类型是由符合Shape 协议的对象定义的关联类型
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")
}
通过添加类型擦除形状,您可以将其传递给函数。
因此,这将构建:
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 Shape Factory索引是Int,而Shapers Club使用UUID ..
正如你所说,此时我们需要“恢复”类型。
这正是查看 AnyHashable 源文档时所解释的内容。
Cast 无法避免,对于应用程序的安全性和模型的稳固性来说,这最终是一件好事。
第一部分是协议,随着情况的增多,可能会比较冗长复杂,但是会在app的通信基础框架中,不应该经常变动。
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 }
}
第二部分是模型 - 随着我们与更多的形状制造商合作,这有望发展。
可以对形状进行的敏感操作不在此代码中。所以创建和调整模型和 api 没有问题。
// 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
}
}
测试
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
就是这样。我希望这可能会有所帮助。
欢迎任何更正或评论。
最后,我为我的 Shapes 制造商的名字感到非常自豪:)