2016-03-02 5 views
1

Я новичок в 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).

myTown и fredTheZombie.town не являются тем же городом. Если вы хотите, чтобы они были одним и тем же экземпляром, сделайте их class (ссылочный тип).

Дополнительная информация о Apple Swift Blog и в Swift 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

Смежные вопросы