Swift中的相互非可选引用循环
考虑以下用例:
在某个游戏的模型中,你有一个Player类.每个玩家都有一个无主的让对手:玩家代表他们正在对抗的对手.这些总是成对创建,并且玩家必须始终拥有对手,因为它是非可选的.然而,这很难建模,因为一个玩家必须先创建另一个玩家,并且第一个玩家在创建第二个玩家之前不会有对手! 通过一些丑陋的黑客攻击,我想出了这个解决方案: class Player { private static let placeholder: Player = Player(opponent: .placeholder,name: "") private init(opponent: Player,name: String) { self.opponent = opponent self.name = name } unowned var opponent: Player let name: String class func getPair(named names: (String,String)) -> (Player,Player) { let p1 = Player(opponent: .placeholder,name: names.0) let p2 = Player(opponent: p1,name: names.1) p1.opponent = p2 return (p1,p2) } } let pair = Player.getPair(named:("P1","P2")) print(pair.0.opponent.name) print(pair.1.opponent.name) 哪个效果很好.但是,我无法将对手变成常数.一种解决方案是让对手成为没有集合的计算属性,由私有var支持,但我想避免这种情况. 我试图用Swift指针进行一些黑客攻击,并提出: class func getPair(named names: (String,Player) { var p1 = Player(opponent: .placeholder,name: names.0 + "FAKE") let p2 = Player(opponent: p1,name: names.1) withUnsafeMutablePointer(to: &p1) { var trueP1 = Player(opponent: p2,name: names.0) $0.moveAssign(from: &trueP1,count: 1) } return (p1,p2) } 但这给了一个段错误.此外,在使用lldb进行调试时,我们可以看到在初始化p1之后,我们有: (lldb) p p1 (Player2.Player) $R3 = 0x0000000101004390 { opponent = 0x0000000100702940 { opponent = <uninitialized> name = "" } name = "P1FAKE" } 但是在函数结束时,lldb显示了这个: (lldb) p p1 (Player2.Player) $R5 = 0x00000001010062d0 { opponent = 0x00000001010062a0 { opponent = 0x0000000101004390 { opponent = 0x0000000100702940 { opponent = <uninitialized> name = "" } name = "P1FAKE" } name = "P2" } name = "P1" } (lldb) p p2 (Player2.Player) $R4 = 0x00000001010062a0 { opponent = 0x0000000101004390 { opponent = 0x0000000100702940 { opponent = <uninitialized> name = "" } name = "P1FAKE" } name = "P2" } 因此p1正确指向p2,但p2仍指向旧p1.更重要的是,p1实际上改变了地址! 我的问题是双重的: >是否有更清晰,更“快捷”的方式来创建这种相互非可选引用的结构? 解决方法
在搞砸了一段时间之后,看起来你想要做的事情可能是不可能的,并且与Swift并没有真正相同.更重要的是,它可能是一个有缺陷的方法开始.
就Swift而言,初始化器需要在返回之前初始化所有存储的值.出于多种原因,我不打算这样做.当初始化时无法保证/计算值时,将使用选项,IUO和计算值.如果您不想要Optionals,IUO或计算值,但仍希望在初始化后取消设置一些存储的值,那么您就想要吃蛋糕并吃掉它. 就设计而言,如果您需要将两个对象链接得如此紧密以至于在初始化时需要彼此,则您的模型(IMO)会被破坏.这是分层数据结构解决得很好的确切问题.在你的具体例子中,似乎很清楚你需要某种Match或Competition对象来创建和管理两个玩家之间的关系,我知道你的问题更接近于“这是否可能”而不是“应该完成”,但我想不出任何不是坏主意的情况.从根本上说它打破了封装. Player对象应该管理和跟踪Player对象中存在的东西,而Player类中唯一的托管关系应该是它的子对象.任何兄弟关系都应该由它的父母访问/设置. 这成为一个更清晰的规模问题.如果你想添加第三个玩家怎么办? 50岁左右?然后,您必须初始化并将每个玩家连接到其他玩家,然后才能使用任何玩家.如果您想要添加或删除播放器,您必须同时为每个连接的播放器执行此操作,并阻止发生任何事情. 另一个问题是它在任何其他情况下都无法使用.如果设计得当,玩家可以在所有类型的游戏中使用.而目前的设计允许它仅在1v1情况下使用.对于任何其他情况,您将不得不重新编写它,您的代码库将会分歧. 总而言之,你想要的东西在Swift中可能是不可能的,但是如果它成为可能的话,反正几乎肯定是一个坏主意:) 对不起文章,希望你觉得它有用! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |