我可以制作一个 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.bike
的 Vehicle
总是有一个 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<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)
但是伙计,这很复杂...
我可以制作一个 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.bike
的 Vehicle
总是有一个 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<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)
但是伙计,这很复杂...