【问题标题】:Can I make a Swift enum generic, so I can use its cases to infer a type for a generic class?我可以制作一个 Swift 枚举泛型,以便我可以使用它的案例来推断泛型类的类型吗?
【发布时间】:2020-06-09 05:25:21
【问题描述】:

我可以创建一个enum 泛型(每种情况的类型不同),以便我可以使用它的情况来推断泛型类的类型吗?

我这里有一个例子:

class Config {
    let name: String
    init(_ name: String) {
        self.name = name
    }
}

class CarConfig: Config {
    static let sports = CarConfig("sports")
    static let van = CarConfig("van")
}

class BikeConfig: Config {
    static let road = BikeConfig("road")
    static let mtb = BikeConfig("mtb")
}

enum VehicleType {
    case car, bike, scooter
}

class Vehicle<C: Config> {

    let type: VehicleType
    let config: C

    init(type: VehicleType, config: C) {
        self.type = type
        self.config = config
    }

}

let bike = Vehicle(type: .bike, config: BikeConfig.mtb)

bike.config.name // mtb

我想做的是像这样启动一个载具:

let bike = Vehicle(type: .bike, config: .mtb)

我希望编译器推断出BikeConfig,所以我可以省略它。我希望编译器知道带有type == VehicleType.bikeVehicle 总是有一个Config,即BikeConfig

显然我必须更改我的Vehicle

class Vehicle<C: Config> {

    let type: VehicleType<C>
    let config: C

    init(type: VehicleType<C>, config: C) {
        self.type = type
        self.config = config
    }

}

现在制作enum VehicleType enum VehicleType&lt;C: Config&gt;

不知道从这里去哪里。有什么帮助吗? :)

[更新:将scooter 的情况添加到VehicleType]

【问题讨论】:

    标签: swift generics enums type-inference inference


    【解决方案1】:

    您可以将 Associated Valuesenum 案例一起使用,作为您想要的任何类型。

    创建enum VehicleTypecase carCarConfigcase bikeBikeConfig 作为关联类型

        enum VehicleType {
            case car(CarConfig)
            case bike(BikeConfig)
        }
    

    现在,class Vehicle 的定义可以修改为

        class Vehicle {
            let type: VehicleType
            init(type: VehicleType) {
                self.type = type
            }
        }
    

    使用创建 Vehicle 实例,

        let bike = Vehicle(type: .bike(.mtb))
    
    

    【讨论】:

    • 这种方法的缺点是不能轻易访问Vehicle的配置。
    【解决方案2】:

    你已经把它倒过来了,你不应该根据枚举值推断泛型类型,因为这意味着你想用一个可能在运行时已知的值来确定一些编译时的东西(泛型类型)(枚举的值)。

    因此,我们需要使type 参数成为仅编译时的东西,即也是一个类型参数。

    您首先介绍一个VehicleTypeProtocol,以及一个为每个枚举案例实现该协议的struct

    protocol VehicleTypeProtocol {
        // this associated type creates the link between a vehicle type and a config type
        associatedtype ConfigType: Config
        // this is so that we can assign to Vehicle.type
        static var type: VehicleType { get }
    }
    
    struct Car : VehicleTypeProtocol {
        typealias ConfigType = CarConfig
        static var type: VehicleType { .car }
    }
    
    struct Bike : VehicleTypeProtocol {
        typealias ConfigType = BikeConfig
        static var type: VehicleType { .bike }
    }
    
    struct Scooter: VehicleTypeProtocol {
        typealias ConfigType = BikeConfig
        static var type: VehicleType { .scooter }
    }
    

    然后初始化器可以这样实现:

    init<T: VehicleTypeProtocol>(type: T.Type, config: C) where T.ConfigType == C {
        self.type = T.type
        self.config = config
    }
    

    用法:

    let bike = Vehicle(type: Bike.self, config: .mtb)
    

    但是,伙计,这很令人费解……

    【讨论】:

      猜你喜欢
      • 2013-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多