6
我決定通過編寫一些簡單的代碼來更好地理解類型擦除。我有一個通用的士兵協議。士兵有武器和士兵可以戰鬥。我想創建不同類型的士兵的軍隊。我認爲這種類型的擦除會爲我提供一種拳擊士兵使用者的手段,這樣我就可以將他們當作純粹的士兵(而不是狙擊手,步兵等)對待。但是我發現中間拳擊類型(類型橡皮擦)必須仍然可以通過士兵的相關類型(即武器)進行通用化。所以,我可以讓步槍揮舞士兵,或火箭揮舞士兵,但不是純粹的士兵。有沒有關於我錯過的類型擦除的使用?類型擦除:我錯過了什麼?
import Foundation
// Soldiers have weapons and soldiers can fight
protocol Weapon {
func fire()
}
protocol Soldier {
associatedtype W: Weapon
var weapon: W { get }
func fight()
}
extension Soldier {
func fight() { weapon.fire() }
}
// Here are some weapons
struct Rifle : Weapon {
func fire() { print("Bullets away!") }
}
struct Rocket : Weapon {
func fire() { print("Rockets away!") }
}
struct GrenadeLauncher : Weapon {
func fire() { print("Grernades away!") }
}
// Here are some soldiers
struct Sniper : Soldier {
var weapon = Rifle()
}
struct Infantryman : Soldier {
var weapon = Rifle()
}
struct Artillaryman : Soldier {
var weapon = Rocket()
}
struct Grenadier : Soldier {
var weapon = GrenadeLauncher()
}
// Now I would like to have an army of soldiers but the compiler will not let me.
// error: protocol 'Soldier' can only be used as a generic constraint because it has Self or associated type requirements
class Army {
var soldiers = [Soldier]()
func join(soldier: Soldier) {
soldiers.append(soldier)
}
func makeWar() {
for soldier in soldiers { soldier.fight() }
}
}
// So, let's try the type erasure technique:
struct AnySoldier<W: Weapon> : Soldier {
var weapon: W
private let _fight:() -> Void
init<S: Soldier>(soldier: S) where S.W == W {
_fight = soldier.fight
weapon = soldier.weapon
}
func fight() { _fight() }
}
var s1 = AnySoldier(soldier: Sniper())
print (type(of: s1)) // AnySoldier<Rifle>
s1.fight() // Bullets away!
s1.weapon.fire() // Bullets away!
s1 = AnySoldier(soldier: Infantryman()) // Still good; Infantrymen use rifles
s1 = AnySoldier(soldier: Grenadier()) // Kaboom! Grenadiers do not use rifles
// So now I can have an army of Rifle wielding Soldiers
class Army {
var soldiers = [AnySoldier<Rifle>]()
func join(soldier: AnySoldier<Rifle>) {
soldiers.append(soldier)
}
func makeWar() {
for soldier in soldiers { soldier.fight() }
}
}
let army = Army()
army.join(soldier: AnySoldier(soldier: Sniper()))
army.join(soldier: AnySoldier(soldier: Infantryman()))
army.join(soldier: AnySoldier(soldier: Grenadier())) // Kaboom! Rifles only
army.makeWar()
// But, what I really want is an army wherein the weapons are unrestricted.
class Army {
var soldiers = [AnySoldier]()
func join(soldier: AnySoldier) {
soldiers.append(soldier)
}
func makeWar() {
for soldier in soldiers { soldier.fight() }
}
}
這樣做,羅布。謝謝。順便說一句:我喜歡你的談話。我會再次觀看Beyond Crusty--只要我抽空觀看原作。 – Verticon