gpt4 book ai didi

swift - 类型删除 : Have I missed Anything?

转载 作者:搜寻专家 更新时间:2023-10-30 22:12:34 24 4
gpt4 key购买 nike

我决定通过编写一些简单的代码来更好地理解类型删除。我有一个通用的 Soldier 协议(protocol)。兵有兵器,兵能战。我想创建由不同类型的士兵组成的军队。我认为类型删除会为我提供一种拳击士兵采用者的方法,这样我就可以将他们视为普通士兵(而不是狙击手、步兵等)但我发现中间的拳击类型(类型橡皮擦)必须仍然在士兵的关联类型(即武器)上通用。所以,我可以让步枪挥舞士兵,或火箭挥舞士兵,但不仅仅是普通士兵。关于类型删除的使用,我是否遗漏了什么?

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

最佳答案

您还需要对 Weapons 进行类型删除:

struct AnyWeapon: Weapon {
private let _fire: () -> Void
func fire() { _fire() }
init<W: Weapon>(_ weapon: W) {
_fire = weapon.fire
}
}

有了这个,AnySoldier 就不需要是通用的了。

struct AnySoldier : Soldier {
private let _fight: () -> Void
let weapon: AnyWeapon

init<S: Soldier>(_ soldier: S) {
_fight = soldier.fight
weapon = AnyWeapon(soldier.weapon)
}

func fight() { _fight() }
}

但不要忽视另一种方法,即用一个简单的函数替换 Weapon 并使 Soldier 成为一个简单的结构。例如:

struct Soldier {
private let weaponFire: () -> Void
func fight() { weaponFire() }
static let sniper = Soldier(weaponFire: { print("Bullets away!") })
}

let sniper = Soldier.sniper
sniper.fight()

我在 Beyond Crusty: Real-World Protocols 中进一步讨论了其中的一些内容.有时您不需要协议(protocol)。

关于swift - 类型删除 : Have I missed Anything?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40980260/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com