2016-03-02 51 views
1

我是Swift和靜態編程的初學者。閱讀大書呆子牧場Swift書。我不明白的是爲什麼myTown人口正在變化,但不是fredTheZombie.town?這次演習要求城鎮人口不要低於零。當人口少於10歲時可能會發生這種情況。如何更改fredTheZombie.town人口變量?Swift - 更改結構中的變量?

struct Town { 
    var population = 5422 
    var numberOfStoplights = 4 

    func printTownDescription() { 
     print("Population: \(myTown.population), number of stoplights: \(myTown.numberOfStoplights)") 
    } 

    mutating func changePopulation(amount: Int) { 
     population += amount 
    } 
} 

class Monster { 
    var town: Town? 
    var name = "Monster" 

    func terrorizeTown() { 
     if town != nil { 
      print("\(name) is terrorizing a town!") 
     } else { 
      print("\(name) hasn't found a town to terrorize yet...") 
     } 
    } 
} 

class Zombie: Monster { 
    var walksWithLimp = true 

    final override func terrorizeTown() { 
     guard town?.population > 0 else { 
      return 
     } 

     if town?.population > 10 { 
      super.town!.changePopulation(-10) 
     } else { 
      super.town!.population = 0 
     } 

     super.terrorizeTown() 
    } 

    func changeName(name: String, walksWithLimp: Bool) { 
     self.name = name 
     self.walksWithLimp = walksWithLimp 
    } 
} 

var myTown = Town() 
myTown.changePopulation(500) 
let fredTheZombie = Zombie() 
fredTheZombie.town = myTown 
fredTheZombie.terrorizeTown() 
fredTheZombie.town?.printTownDescription() 
fredTheZombie.changeName("Fred the Zombie", walksWithLimp: false) 

myTown.changePopulation(-5915) 
print(myTown.population) 
print(fredTheZombie.town!.population) 
fredTheZombie.terrorizeTown() 
fredTheZombie.terrorizeTown() 
fredTheZombie.town?.printTownDescription() 

輸出:

Monster is terrorizing a town! 
Population: 5922, number of stoplights: 4 
7 
5912 
Fred the Zombie is terrorizing a town! 
Fred the Zombie is terrorizing a town! 
Population: 7, number of stoplights: 4 
Program ended with exit code: 0 

回答

2

Town是一個結構,值類型。將值類型分配給其他變量(例如fredTheZombie.town = myTown)時,將複製該值類型(表示創建的新值爲Town的值與原始值Town相同)。

myTownfredTheZombie.town不再是同一個城鎮。如果你想讓它們成爲同一個實例,請將它們設爲class(引用類型)。

查看更多關於Apple Swift BlogSwift Language Guide的信息。

我們遇到的最大問題是可選結構。解包可選結構的結果(使用town!)又是一個副本,一個新城鎮。要解決這一點,你必須:

var myTown = super.town! 
myTown.changePopulation(-10) 
super.town = myTown // assign back 

整體例如:

struct Town { 
    var population = 5422 
    var numberOfStoplights = 4 

    func printTownDescription() { 
     // note you have to print "self" here, not "myTown" 
     print("Population: \(self.population), number of stoplights: \(self.numberOfStoplights)") 
    } 

    mutating func changePopulation(amount: Int) { 
     population += amount 
    } 
} 

class Monster { 
    var town: Town? 
    var name = "Monster" 

    func terrorizeTown() { 
     if town != nil { 
      print("\(name) is terrorizing a town!") 
     } else { 
      print("\(name) hasn't found a town to terrorize yet...") 
     } 
    } 
} 

class Zombie: Monster { 
    var walksWithLimp = true 

    final override func terrorizeTown() { 
     guard super.town?.population > 0 else { 
      return 
     } 

     var town = super.town! 

     if town.population > 10 { 
      town.changePopulation(-10) 
     } else { 
      town.population = 0 
     } 

     super.town = town 

     super.terrorizeTown() 
    } 

    func changeName(name: String, walksWithLimp: Bool) { 
     self.name = name 
     self.walksWithLimp = walksWithLimp 
    } 
} 

在你的情況下,沒有必要town是真正可選的。您可以將它傳遞給構造函數中的Monster

+0

這很有道理。有沒有辦法改變fredTheZombie.town而不把它變成同一個實例(myTown)? – ltrainpr

+0

@ltrainpr您可以指定任何變量或調用變異方法。但是,因爲'fredTheZombie.town'是一個可選項,所以它不會真正起作用,因爲解包的結果又是一個副本。處理值類型的最常見方式是始終創建一個新實例。 – Sulthan

+0

@ltrainpr哦,我現在看到你的問題,讓我編輯答案。 – Sulthan