Swift Set插入同ID对象未替换旧值,是特性还是用法有误?
Swift Set插入相同标识元素时不替换的原因及解决方法
这是Swift Set的既定工作机制,并非你的用法错误。
核心原因
Swift的Set依赖Hashable协议实现元素唯一性,判定逻辑为:
- 两个元素的哈希值相等(通过
hash(into:)计算) - 两个元素通过
==运算符判定为相等
当向Set插入元素时,若集合中已存在相等的元素,insert方法会直接忽略新元素——因为Set认为这两个元素是同一个对象,无需替换。
结合你的代码来看:你为Object自定义的Equatable和Hashable实现仅以id作为判定依据,这意味着只要id相同,两个Object就会被Set视为同一元素。因此插入obj2时,Set检测到已有相等的obj1,自然不会替换旧元素。
解决方法
根据业务需求,可选择以下两种处理方式:
1. 保留id作为唯一标识,需要更新其他属性
若你需要用id区分唯一对象,且希望新元素覆盖旧元素,可以先移除旧元素再插入新元素:
var collection = Set<Object>() let obj1 = Object(id: "1", action: .delete, code: 1) collection.insert(obj1) let obj2 = Object(id: "1", action: .update, code: 4) // 利用相等性判定移除旧元素 collection.remove(obj2) collection.insert(obj2) print(collection.first!.description) // 输出:`update` on `1` with #4
更简洁的方案是使用字典,以id为键存储对象,字典赋值时会自动覆盖相同键的值:
var collectionDict = [String: Object]() let obj1 = Object(id: "1", action: .delete, code: 1) collectionDict[obj1.id] = obj1 let obj2 = Object(id: "1", action: .update, code: 4) collectionDict[obj2.id] = obj2 print(collectionDict["1"]!.description) // 输出:`update` on `1` with #4
2. 将其他属性纳入唯一性判定
若不同action或code的Object应被视为不同元素,需修正Equatable和Hashable实现,把所有相关属性纳入判断:
struct Object: Equatable, Hashable { let id: String let action: Action let code: UInt8 var description: String { return "`\(self.action)` on `\(self.id)` with #\(self.code)" } init(id: String, action: Action, code: UInt8) { self.id = id self.action = action self.code = code } func hash(into hasher: inout Hasher) { hasher.combine(self.id) hasher.combine(self.action) hasher.combine(self.code) } static func == (lhs: Object, rhs: Object) -> Bool { return lhs.id == rhs.id && lhs.action == rhs.action && lhs.code == rhs.code } }
修改后,obj1和obj2会被视为不同元素,插入后Set中会同时存在两个对象(需确保业务逻辑允许)。
内容的提问来源于stack exchange,提问作者Youmate
相关产品推荐
相关产品推荐

