我可以制作一个 Swift 枚举泛型,以便我可以使用它的案例来推断泛型 class 的类型吗?

Can I make a Swift enum generic, so I can use its cases to infer a type for a generic class?

我可以制作一个 enum 泛型(每个案例的类型不同),这样我就可以使用它的案例来推断泛型 class 的类型吗?

我这里有一个例子:

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 总是有一个 ConfigBikeConfig.

显然我必须改变我的 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<C: Config>.

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

[更新:将 scooter 个案例添加到 VehicleType]

您可以将关联值enum案例一起使用,作为您想要的任何类型。

创建 enum VehicleType with case car with CarConfig and case bike with BikeConfig 作为 关联类型,

    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))

你搞反了,你不应该根据枚举值推断泛型类型,因为这意味着你想确定一些编译时的东西(泛型类型),其值可能在运行时(枚举的值)。

因此,我们需要使 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)

但是伙计,这很复杂...