2016-12-05 7 views
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() } 
    } 
} 

उत्तर

5

आप टाइप-मिटाने के लिए हथियार के रूप में अच्छी तरह से की जरूरत है:

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

एक और दृष्टिकोण को नजरअंदाज न करें, हालांकि, एक सरल कार्य के साथ हथियार को प्रतिस्थापित करना और सैनिक को एक साधारण संरचना बनाना है। उदाहरण के लिए:

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 में चर्चा करता हूं। कभी-कभी आप प्रोटोकॉल नहीं चाहते हैं।

+0

ऐसा किया, रॉब। धन्यवाद। बीटीडब्ल्यू: मुझे आपकी वार्ता पसंद है। मैं फिर से क्रिस्टी से परे देख रहा हूं - जैसे ही मैं मूल देखने के लिए समय निकालता हूं। – Verticon

संबंधित मुद्दे

 संबंधित मुद्दे