Swift枚举:忽略关联值枚举唯一用例,实现连续整数映射
问题翻译
我希望实现快速枚举,将Score枚举转换为从0开始的连续唯一整数值序列,每个枚举case对应一个值,赋值顺序与声明顺序一致。在这个示例中,序列应为0、1、2。有没有现成的表达式可以实现这个需求?还是只能手动编写?另外我需要两种Hashable实现,以便分别统计所有可能的变体数量(包含关联值的不同组合)和枚举case的总数。
提供的代码示例:
enum Score: { case snap(Rank) // 6 varieties case double(Power) // 4 varieties case highFive var value: Int { // ... } } enum Rank: Int { //.. } enum Power: Int { // .. }
解决方案
1. 给每个枚举Case分配连续值(0、1、2)
不需要手动逐个赋值,通过switch语句映射每个case到对应索引即可,完全匹配声明顺序:
enum Score: Hashable { case snap(Rank) case double(Power) case highFive // 每个case对应的连续值,按声明顺序分配0、1、2 var caseValue: Int { switch self { case .snap: return 0 case .double: return 1 case .highFive: return 2 } } }
如果想更自动化(比如新增case时无需修改caseValue),可以手动实现CaseIterable协议(带关联值的枚举无法自动合成该协议),通过allCases的索引获取值:
extension Score: CaseIterable { // 按声明顺序定义所有case的代表实例(关联值不影响case判断) static var allCases: [Score] { [.snap(.one), .double(.low), .highFive] } } // 基于CaseIterable的caseValue实现 var caseValue: Int { Score.allCases.firstIndex(of: self)! }
注意:需保证allCases的顺序与枚举声明顺序一致,且该方式仅适用于只关心case本身、不关联具体关联值的场景。
2. 给所有变体(Case+关联值组合)分配连续值
如果需要给每个包含关联值的具体变体分配唯一连续值(比如snap(Rank.one)对应0,snap(Rank.two)对应1…highFive对应10),可以结合关联枚举的CaseIterable和rawValue实现:
// 先让Rank和Power实现CaseIterable与Int rawValue enum Rank: Int, CaseIterable { case one, two, three, four, five, six // 共6种 } enum Power: Int, CaseIterable { case low, medium, high, extreme // 共4种 } enum Score: Hashable { case snap(Rank) case double(Power) case highFive var variantValue: Int { switch self { case .snap(let rank): // snap的变体从0开始,对应Rank的rawValue return rank.rawValue case .double(let power): // double的变体接在snap之后,先加snap的总数 return Rank.allCases.count + power.rawValue case .highFive: // highFive接在所有snap和double变体之后 return Rank.allCases.count + Power.allCases.count } } }
3. 两种Hashable实现
- 默认合成的Hashable:Swift会自动为
Score合成Hashable实现(只要Rank和Power也实现Hashable),该实现会同时考虑case和关联值,不同的变体(比如.snap(.one)和.snap(.two))会被视为不同的哈希对象,适合统计变体总数。 - 仅按Case哈希的实现:如果需要只区分case、忽略关联值的哈希逻辑,可以手动实现自定义哈希结构:
extension Score { struct CaseOnlyHash: Hashable { private let caseIndex: Int init(_ score: Score) { switch score { case .snap: self.caseIndex = 0 case .double: self.caseIndex = 1 case .highFive: self.caseIndex = 2 } } func hash(into hasher: inout Hasher) { hasher.combine(caseIndex) } static func == (lhs: Self, rhs: Self) -> Bool { lhs.caseIndex == rhs.caseIndex } } }
使用时只需将Score实例包装为CaseOnlyHash,即可按case进行哈希比较,适合统计枚举case总数。
4. 统计总数
- 枚举case总数:可以直接硬编码
3,或通过手动实现的CaseIterable的Score.allCases.count获取。 - 变体总数:通过
Rank.allCases.count + Power.allCases.count + 1计算(+1对应无关联值的highFive)。
内容的提问来源于stack exchange,提问作者bobby123uk
相关产品推荐
相关产品推荐

