Jan*_*Jan 5 generics type-systems protocols swift
Swift 5.7 引入了主要关联类型。在尝试此功能时,我想知道是否仍然存在类型擦除类型(例如 AnySequence)的用例,或者主要关联类型是否会使这些类型完全过时?
\n例如,如果我们有以下代码:
\nprotocol Car<Fuel> {\n    associatedtype Fuel\n    func drive(fuel: Fuel)\n}\n\nstruct Electricity {}\nstruct Petrol {}\n\nstruct SportsCar: Car {\n    func drive(fuel: Petrol) { print("\xef\xb8\x8f") }\n}\n\nstruct FamilyCar: Car {\n    func drive(fuel: Electricity) { print("") }\n}\n\nstruct WorkCar: Car {\n    func drive(fuel: Electricity) { print("") }\n}\n我们现在可以制作一个仅包含电动汽车的数组:
\nlet electricCars: [any Car<Electricity>] = [FamilyCar(), WorkCar()]\n以前我会写这样的东西:
\nstruct AnyCar<Fuel>: Car {\n   //Implementation\n}\n\nlet electricCars: = [AnyCar(FamilyCar()), AnyCar(WorkCar())]\n是否仍然存在自定义结构“AnyCar”有意义的情况?
\n谢谢你!
\n尽管主要关联类型确实有助于消除使用某些存在类型的许多边缘,但仍然存在使用具体类型进行手动类型擦除的用例Any\xe2\x80\xa6。
存在类型动态地调度其接口声明的方法直至底层值,但关键的是,它们本身不能:
\n一个非常常见的例子是Equatable一致性。我们可以更新Car协议以采用Equatable一致性,以表明Cars 应该能够相等:
protocol Car<Fuel>: Equatable {\n    associatedtype Fuel\n    func drive(fuel: Fuel)\n}\n\nstruct SportsCar: Car { \xe2\x80\xa6 }\nstruct FamilyCar: Car { \xe2\x80\xa6 }\nstruct WorkCar: Car { \xe2\x80\xa6 }\nCar但是,虽然如果知道两个值的静态类型,则可以检查两个值是否相等,但无法检查两个any Car值是否相等:
WorkCar() == WorkCar() // \xe2\x9c\x85 true\n\nlet electricCars: [any Car<Electricity>] = [WorkCar(), WorkCar()]\nelectricCars[0] == electricCars[1]\n//  Type \'any Car<Electricity>\' cannot conform to \'Equatable\'\n//    Only concrete types such as structs, enums, and classes can conform to protocols\n//    Required by referencing operator function \'==\' on \'Equatable\' where \'Self\' = \'any Car<Electricity>\'\nEquatable有无法满足Self的要求any Car;AnyCar但是,如果您编写自己的类型,则可以这样做:
struct AnyCar<Fuel>: Car {\n    private let inner: any Car<Fuel>\n    private let isEqual: (AnyCar<Fuel>) -> Bool\n\n    // The key to the `Equatable` conformance is capturing the _static_ type\n    // of the value we\'re wrapping.\n    init<C: Car<Fuel>>(_ car: C) {\n        inner = car\n        isEqual = { anyCar in\n            guard let otherCar = anyCar.inner as? C else {\n                return false\n            }\n\n            return car == otherCar\n        }\n    }\n\n    func drive(fuel: Fuel) {\n        inner.drive(fuel: fuel)\n    }\n\n    static func ==(_ lhs: Self, _ rhs: Self) -> Bool {\n        lhs.isEqual(rhs)\n    }\n}\n使用这个包装器,您可以检查两个任意AnyCar值是否相等:
let electricCars: [AnyCar<Electricity>] = [AnyCar(FamilyCar()), AnyCar(WorkCar()), AnyCar(WorkCar())]\nelectricCars[0] == electricCars[1] // \xe2\x9c\x85 false\nelectricCars[1] == electricCars[2] // \xe2\x9c\x85 true\n这种方法对于您来说可能看起来很熟悉,AnyHashable因为它用作可以包含任何类型键的字典的通用键类型。您无法使用以下方法实现相同的功能any Hashable:
let d: [any Hashable: Any] = ["hi" : "there"] //  Type \'any Hashable\' cannot conform to \'Hashable\'\n与 , 相反AnyCar,AnyHashable它的好处是如此普遍和必要,编译器会自动将类型包装起来,AnyHashable这样您就不需要自己做这件事,从而使其基本上不可见。