下面的代码是我的代码的极其简化的版本,但它更清楚.所以我真正想要的是这样的:
原始场景 – 未解决
protocol Motor { var power: Int { get } }protocol Vehicle { associatedType Engine: Motor var engine: Engine { get }}protocol Transportation { associatedType Transport: Vehicle var transport: Transport { get }}
然后我想输入erase Transportation并且能够存储一个AnyTransportation阵列,它可以拥有任何可以拥有任何Motor的车辆.
所以这是一个包含3个协议的场景,其中2个具有(嵌套)关联类型.
我不知道该怎么做.实际上,我甚至不知道如何解决更简单的场景:
简化的场景 – 未解决
我们可以将上面的原始场景简化为我们有2个协议的版本,其中只有1个协议具有关联类型:
protocol Vehicle { var speed: Int { get }}protocol Transportation { associatedtype Transport: Vehicle var transport: Transport { get } var name: String { get }}
然后我们说我们有一辆符合车辆的巴士:
struct Bus: Vehicle { var speed: Int { return 60 }}
然后我们有两个不同的Buslines,RedBusline和BlueBusline都符合Transportation
struct RedBusline: Transportation { let transport: Bus var name = "Red line" init(transport: Bus = Bus()) { self.transport = transport }}struct BlueBusline: Transportation { let transport: Bus var name = "Blue line" init(transport: Bus = Bus()) { self.transport = transport }}
然后我们可以使用基本和框图案和类键入擦除传输,如bignerdranch here所述:
final class AnyTransportation<_Transport: Vehicle>: Transportation { typealias Transport = _Transport private let Box: _AnyTransportationBase<Transport> init<Concrete: Transportation>(_ concrete: Concrete) where Concrete.Transport == Transport { Box = _AnyTransportationBox(concrete) } init(transport: Transport) { fatalError("Use type erasing init instead") } var transport: Transport { return Box.transport } var name: String { return Box.name }}final class _AnyTransportationBox<Concrete: Transportation>: _AnyTransportationBase<Concrete.Transport> { private let concrete: Concrete init(_ concrete: Concrete) { self.concrete = concrete; super.init() } required init(transport: Transport) { fatalError("Use type erasing init instead") } overrIDe var transport: Transport { return concrete.transport } overrIDe var name: String {return concrete.name }}class _AnyTransportationBase<_Transport: Vehicle> : Transportation { typealias Transport = _Transport init() { if type(of: self) == _AnyTransportationBase.self { fatalError("Use Box class") } } required init(transport: Transport) { fatalError("Use type erasing init instead") } var transport: Transport { fatalError("abstract") } var name: String { fatalError("abstract") }}
然后我们可以放入RedBusline或BlueBusline
let busRIDes: [AnyTransportation<Bus>] = [AnyTransportation(RedBusline()),AnyTransportation(BlueBusline())]busRIDes.forEach { print(struct Ferry: Vehicle { var speed: Int { return 40 }}struct Ferryline: Transportation { let transport: Ferry = Ferry() var name = "Ferry line"}.name) } // prints "Red line\nBlue line"
在关于与上面链接的类型擦除的博客文章中,我想要的实际上是Homogeneous Requirement的解决方法.
想象一下,我们有另一辆车,例如渡轮和Ferryline:
final class AnyVehicle: Vehicle { private let Box: _AnyVehicleBase init<Concrete: Vehicle>(_ concrete: Concrete) { Box = _AnyVehicleBox(concrete) } var speed: Int { return Box.speed }}final class _AnyVehicleBox<Concrete: Vehicle>: _AnyVehicleBase { private let concrete: Concrete init(_ concrete: Concrete) { self.concrete = concrete; super.init() } overrIDe var speed: Int { return concrete.speed }}class _AnyVehicleBase: Vehicle { init() { if type(of: self) == _AnyVehicleBase.self { fatalError("Use Box class") } } var speed: Int { fatalError("abstract") }}// THIS DOES NOT WORKlet rIDes: [AnyTransportation<AnyVehicle>] = [AnyTransportation(AnyVehicle(RedBusline())),AnyTransportation(AnyVehicle(Ferryline()))] // COMPILE ERROR: error: argument type 'RedBusline' does not conform to expected type 'Vehicle'
我想我们现在要输入擦除车辆?因为我们想要一个AnyTransportation< AnyVehicle>的数组,对吧?
let transportations: [AnyTransportation<AnyVehicle<AnyMotor>>] = [Busline(),Ferryline()] // want to put `Busline` and `Ferryline` in same array
当然这不起作用……因为AnyTransportation期望传递符合Transportation的类型,但AnyVehicle当然不符合它.
但我无法找到解决方案.有没有?
问题1:是否可以键入擦除简单场景允许:[AnyTransportation< AnyVehicle>]?
问题2:如果简单场景是可解决的,原始场景是否也可以解决?
下面仅详细说明我希望通过原始场景实现的目标
原始场景 – 扩展
我最初的需要是将任何具有任何车辆的交通工具放在同一阵列中的任何电机:
protocol Motor { var power: Int { get }}protocol Vehicle { associatedtype Engine : Motor var engine: Engine { get }}protocol Transportation { associatedtype Transport : Vehicle var transport: Transport { get } var name: String { get set }}// we need the concrete AnyMotor wrapper,as Motor is not a type that conforms to Motor// (as protocols don't conform to themselves).struct AnyMotor : Motor { // we can store base directly,as Motor has no associated types. private let base: Motor // protocol requirement just forwards onto the base. var power: Int { return base.power } init(_ base: Motor) { self.base = base }}struct AnyVehicle : Vehicle { // we cannot directly store base (as Vehicle has an associated type). // however we can *capture* base in a closure that returns the value of the property,// wrapped in its type eraser. private let _getEngine: () -> AnyMotor var engine: AnyMotor { return _getEngine() } init<Base : Vehicle>(_ base: Base) { self._getEngine = { AnyMotor(base.engine) } }}struct AnyTransportation : Transportation { private let _getTransport: () -> AnyVehicle private let _getname: () -> String private let _setname: (String) -> VoID var transport: AnyVehicle { return _getTransport() } var name: String { get { return _getname() } set { _setname(newValue) } } init<Base : Transportation>(_ base: Base) { // similar pattern as above,just multiple stored closures. // however in this case,as we have a mutable protocol requirement,// we first create a mutable copy of base,then have all closures capture // this mutable variable. var base = base self._getTransport = { AnyVehicle(base.transport) } self._getname = { base.name } self._setname = { base.name = } }}struct PetrolEngine : Motor { var power: Int}struct Ferry: Vehicle { var engine = PetrolEngine(power: 100)}struct Ferryline: Transportation { let transport = Ferry() var name = "Ferry line"}var anyTransportation = AnyTransportation(Ferryline())print(anyTransportation.name) // Ferry lineprint(anyTransportation.transport.engine.power) // 100anyTransportation.name = "Foo bar ferrIEs"print(anyTransportation.name) // Foo bar ferrIEs解决方法 如果您想用任何带有任何引擎的车辆表达任何交通工具,那么您需要3个箱子,每个箱子都按照“之前”类型擦除的包装纸进行交谈.您不希望在任何这些框上使用通用占位符,因为您希望根据完全异构的实例进行讨论(例如,不是任何具有特定车辆类型的运输,或任何具有特定电机类型的车辆).
此外,不是使用类层次结构来执行类型擦除,而是可以使用闭包,这允许您捕获基本实例而不是直接存储它.这允许您从原始代码中删除大量样板.
例如:
请注意,尽管Motor没有任何关联类型,我们仍然构建了AnyMotor.这是因为protocols don’t conform to themselves,所以我们不能使用Motor本身来满足Engine相关类型(需要:Motor) – 我们目前必须为它构建一个具体的包装器类型.
总结以上是内存溢出为你收集整理的ios – Swift:嵌套类型擦除全部内容,希望文章能够帮你解决ios – Swift:嵌套类型擦除所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)