使用Swift枚举建模Minecraft NBT格式的优化方案问询
Minecraft NBT格式建模的设计优化问题
我正在为读写Minecraft存档建模NBT格式,确定用枚举是最优方案——因为类型数量固定且不可修改,必须全覆盖,嵌套列表的场景用其他方式很难处理。NBT支持嵌套结构,也允许存储单一NBT类型的列表(包括列表嵌套,比如[[Int],[Double]]是合法的),列表只能包含同一种标签类型,但所有列表都被视为同一类型。另外规范要求部分数组有重复存储方式,比如[Int8]既可以存为byteArray,也可以存为List<Byte>。
目前我的实现能正常运行,但担心存在设计缺陷:我定义了两个重复的枚举Tag和TagList,因为列表嵌套的需求没法合并,想找更合理的实现方式。
当前代码实现:
public enum Tag : Equatable { case end case byte(Int8) case short(Int16) case int(Int32) case long(Int64) case float(Float) case double(Double) case byteArray([Int8]) case string(String) case list(TagList) case compound([String : Tag]) case intArray([Int32]) case longArray([Int64]) } public enum TagList : Equatable { case end case byte([Int8]) case short([Int16]) case int([Int32]) case long([Int64]) case float([Float]) case double([Double]) case byteArray([[Int8]]) case string([String]) case list([List]) case compound([[String : Tag]]) case intArray([[Int32]]) case longArray([[Int64]]) }
优化方案:合并枚举,用关联值承载列表元信息
你可以把TagList的逻辑完全整合到Tag中,通过给list关联值添加元素类型标识,配合Tag自身的嵌套特性解决列表嵌套问题,同时避免重复定义。
第一步:定义标签类型枚举
先单独定义一个TagType枚举,用来标识所有NBT规范中的标签类型,方便后续校验和序列化:
public enum TagType: UInt8, Equatable { case end = 0 case byte = 1 case short = 2 case int = 3 case long = 4 case float = 5 case double = 6 case byteArray = 7 case string = 8 case list = 9 case compound = 10 case intArray = 11 case longArray = 12 }
第二步:重构Tag枚举
让list关联值包含元素类型和元素数组,其中元素数组直接用[Tag]类型——因为每个列表元素本身就是一个Tag,天然支持嵌套:
public enum Tag: Equatable { case end case byte(Int8) case short(Int16) case int(Int32) case long(Int64) case float(Float) case double(Double) case byteArray([Int8]) case string(String) // 列表:元素类型 + 元素集合(元素本身就是Tag,支持嵌套) case list(elementType: TagType, elements: [Tag]) case compound([String: Tag]) case intArray([Int32]) case longArray([Int64]) }
方案优势
- 消除重复定义:不再需要两个枚举,所有NBT类型都统一在
Tag中处理 - 天然支持嵌套:
elements是[Tag]类型,而Tag可以是list,直接实现[[Int],[Double]]这类嵌套场景 - 符合规范要求:通过
elementType明确列表的元素类型,读写时可直接据此校验、序列化/反序列化 - 兼容重复存储场景:比如
[Int8]既可以用.byteArray([1,2,3]),也可以用.list(elementType: .byte, elements: [.byte(1), .byte(2), .byte(3)]),完全满足规范
额外补充:列表合法性校验
可以给Tag扩展一个校验方法,确保列表元素类型和声明的elementType一致:
extension Tag { // 获取当前Tag对应的类型 var tagType: TagType { switch self { case .end: return .end case .byte: return .byte case .short: return .short case .int: return .int case .long: return .long case .float: return .float case .double: return .double case .byteArray: return .byteArray case .string: return .string case .list: return .list case .compound: return .compound case .intArray: return .intArray case .longArray: return .longArray } } // 校验列表元素是否符合类型要求 var isValidList: Bool { guard case .list(let elementType, let elements) = self else { return true // 非列表类型默认合法 } return elements.allSatisfy { $0.tagType == elementType } } }
内容的提问来源于stack exchange,提问作者Ter Maxima
相关产品推荐
相关产品推荐

