我想改变存储在数组中的Swift结构中的属性。 我做了一次重新分配的舞蹈,但感觉不对。
我鼓励尽可能使用Struct,但是这个相对简单的用例(下面)正在推动我使用类(参考类型)。
我应该Classes
使用Game
和/或Player
吗?
请在下面找到代码示例..附带UnitTest
测试摘要
•创建游戏
•创建两个玩家
•将两个玩家添加到游戏中
•向Game发送消息以减少人数
•游戏迭代收集(players
)
•查找玩家并发送消息减量分数
•测试失败 - 玩家'分数不如预期的那样(分别为60和70)
struct Game {
fileprivate(set) var players = [Player]()
}
extension Game {
mutating func addPlayer(_ player: Player) {
players.append(player)
}
mutating func decrementPlayer(_ decrementPlayer: Player, byScore: Int) {
for var player in players {
if player == decrementPlayer {
player.decrementScore(by: byScore)
}
}
}
}
struct Player {
var name: String
var score: Int
init(name: String, score: Int) {
self.name = name
self.score = score
}
mutating func decrementScore(by byScore: Int) {
self.score -= byScore
}
}
extension Player: Equatable {
public static func ==(lhs: Player, rhs: Player) -> Bool {
return lhs.name == rhs.name
}
}
class GameTests: XCTestCase {
var sut: Game!
func testDecrementingPlayerScores_isReflectedCorrectlyInGamePlayers() {
sut = Game()
let player1 = Player(name: "Ross", score: 100)
let player2 = Player(name: "Mary", score: 100)
sut.addPlayer(player1)
sut.addPlayer(player2)
XCTAssertEqual(2, sut.players.count) // Passes
sut.decrementPlayer(player1, byScore: 40)
sut.decrementPlayer(player2, byScore: 30)
XCTAssertEqual(60, sut.players[0].score) // Fails - score is 100 .. expecting 60
XCTAssertEqual(70, sut.players[1].score) // Fails - score is 100 .. expecting 70
}
}
答案 0 :(得分:3)
我鼓励尽可能使用Struct
是的,这是有问题的。建议您使用struct
s 相应的。一般来说,我发现struct
并不总是与时尚指示一样合适。
你的问题是for var player ...
语句实际上是每个玩家的可变副本,因为它会迭代并修改副本。如果你想坚持struct
,你可能需要采用更实用的方法。
mutating func decrementPlayer(_ decrementPlayer: Player, byScore: Int) {
players = players.map {
return $0 == decrementPlayer ? $0.scoreDecrementedBy(by: byScore) : $0
}
}
或者更传统(并且几乎肯定更有效)的方式是找到你想要的玩家的索引
mutating func decrementPlayer(_ decrementPlayer: Player, byScore: Int) {
if let index = players.index(of: decrementPlayer)
{
players[index].decrementScore(by: byScore)
}
}
答案 1 :(得分:0)
我想改变存储在数组中的Swift结构中的属性。我做了一次重新分配的舞蹈,但感觉不对。
嗯,这就是你必须要做的事情,因为结构不是可变的。如果你想能够在适当的位置(在数组中)改变对象,你需要一个类。
答案 2 :(得分:0)
在决定值类型(结构)和引用类型(类)之间应该问的问题是否有意义才能有重复的实例。
例如,取5号,这是一个Int。你可以多次复制它,它很便宜(如结构一样),如果复制也不会造成问题。
现在让我们考虑FileHandle
。它可以是一个结构吗?是。它应该是一个结构吗?不能。使它成为一个结构意味着只要作为参数传递或存储为属性,句柄就会被复制。意味着每个人都会对该句柄有不同的引用(故意忽略copy-on-write)。如果一个引用持有者决定关闭句柄,则会间接使所有其他FileHandle
引用无效,这可能会触发意外行为。
在你的特定情况下,我要说Player
,一个班级。我假设玩家也会有一些UI效果,所以成为一个参考类型是有道理的。但是,如果Player
仅用于统计目的,则将其设为结构。