我可以使Swift枚举泛型,以便可以使用其大小写来为泛型类推断类型吗?

时间:2020-02-25 13:02:47

标签: swift generics enums type-inference inference

我可以制作一个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,因此可以省略它。我希望编译器知道带有Vehicle的{​​{1}}总是有一个type == VehicleType.bike的{​​{1}}。

我显然必须更改我的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 } }

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

[UPDATE:向enum VehicleType添加了enum VehicleType<C: Config>大小写

2 个答案:

答案 0 :(得分:4)

您可以将{strong> Associated Values 与enum案例一起使用,作为所需的任何类型。

使用enum VehicleTypecase carCarConfigcase bike创建BikeConfig作为关联类型

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

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

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

使用创建车辆实例,

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

答案 1 :(得分: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)

但是,伙计,这令人费解...