I need to declare an array like this:
var cups: [Cup<Drink>] = []
The Cup
is a struct and the Drink
is a protocol, but I got the following error:
Value of protocol type 'Drink' cannot conform to 'Drink'; only struct/enum/class types can conform to protocols
I know the protocol type 'Drink' can be erased by a AnyDrink
struct, the flowing code is an example.
But in fact, the Type-Erasure will become extremely complicated when associatetype
, Self
and static-method (in the case of non-final class adopts Drink
, such as the protocol Equatable
with static method ==
) are used in Drink
.
Is there a better way to declare the cups
array?
Or: Is there any easy way to make Type-Erasure? It should be a builtin feature.
protocol Drink {
...
}
struct AnyDrink: Drink {
let drink: Drink
...
}
struct Water: Drink {
...
}
struct Coffee: Drink {
...
}
struct Tea: Drink {
...
}
struct Cup<T: Drink> {
private(set) var drink: T?
mutating func bottomUp() {
drink = nil
}
}
struct Waiter {
var cups: [Cup<AnyDrink>] = []
mutating func makeACupOfSth(_ cup: Cup<AnyDrink>) {
cups.append(cup)
}
mutating func pleaseGiveMeACupOfSthToDrink() -> Cup<AnyDrink> {
return cups.removeFirst()
}
static func excuse(_ customer: Customer) -> Waiter {
return Waiter()
}
}
struct Customer {
var me: Self { self }
func drink() {
var waiter = Waiter.excuse(me)
var cup = waiter.pleaseGiveMeACupOfSthToDrink()
cup.bottomUp()
}
}
For question Is there a better way to declare the cups array?:
You can use another protocol called DrinkGeneric like this and implement it by Cup Struct:
protocol DrinkGeneric {
func sample()
func typOfDrink() -> Drink.Type
}
struct Cup<T: Drink>: DrinkGeneric {
public var drink: T?
mutating func bottomUp() {
drink = nil
}
public func typeOfDrink() -> Drink.Type {
return type(of: drink!)
}
func sample() {
print("sample")
}
}
Then create an array with type DrinkGeneric like this:
var cups: [DrinkGeneric] = [Cup(drink: Water()), Cup(drink: Tea())]
For check type:
if cups[0].typeOfDrink() is Water.Type {
// Any work
}