-
-
Save LeeKahSeng/a347da1778c71f55537eda991bd56c64 to your computer and use it in GitHub Desktop.
protocol Vehicle { | |
associatedtype FuelType: Fuel | |
var name: String { get } | |
func startEngin() | |
func fillGasTank(with fuel: FuelType) | |
} | |
struct Car: Vehicle { | |
let name: String | |
func startEngin() { | |
print("\(name) enjin started!") | |
} | |
func fillGasTank(with fuel: Gasoline) { | |
print("Fill \(name) with \(fuel.name).") | |
} | |
} | |
struct Bus: Vehicle { | |
let name: String | |
func startEngin() { | |
print("\(name) enjin started!") | |
} | |
func fillGasTank(with fuel: Diesel) { | |
print("Fill \(name) with \(fuel.name).") | |
} | |
} | |
protocol Fuel { | |
associatedtype FuelType where FuelType == Self | |
static func purchase() -> FuelType | |
} | |
struct Gasoline: Fuel { | |
let name = "gasoline" | |
static func purchase() -> Gasoline { | |
print("Purchase gasoline from gas station.") | |
return Gasoline() | |
} | |
} | |
struct Diesel: Fuel { | |
let name = "diesel" | |
static func purchase() -> Diesel { | |
print("Purchase diesel from gas station.") | |
return Diesel() | |
} | |
} | |
// MARK: - Functions | |
func startAllEngin(for vehicles: [any Vehicle]) { | |
for vehicle in vehicles { | |
vehicle.startEngin() | |
} | |
} | |
func fillAllGasTank(for vehicles: [any Vehicle]) { | |
for vehicle in vehicles { | |
fillGasTank(for: vehicle) | |
} | |
} | |
func fillGasTank(for vehicle: some Vehicle) { | |
let fuel = type(of: vehicle).FuelType.purchase() | |
vehicle.fillGasTank(with: fuel) | |
} | |
// MARK: - Execution | |
let vehicles: [any Vehicle] = [ | |
Car(name: "Car_1"), | |
Car(name: "Car_2"), | |
Bus(name: "Bus_1"), | |
Car(name: "Car_3"), | |
] | |
startAllEngin(for: vehicles) | |
fillAllGasTank(for: vehicles) |
Came across your blog a short while ago and I like the style! Great article, easy to understand with examples. Quite new to generics (and maybe Swift) so thanks a lot for sharing! I wanted something like this last year but couldn't figure out how, and I read online about type erasure to make it work (AnyMyBaseClassObject). Do you have an article on type erasure?
As for this, is it possible to do something like as some Vehicle
or some kind of explicit cast without creating a new function? And what about changing any
to some
for func fillAllGasTank(for vehicles: [any Vehicle])
, will that work?
As of now (Swift 5.7), there is only 1 way to convert opaque type to existential type and vice versa, which is by using a function parameter. Thus using as
will not work. Furthermore, in order for the conversion to work, the function parameter must be of type any
or some
, using [any]
or [some]
will not work.
I confirm that with beta 4, it works!