You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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])
}

方案优势

  1. 消除重复定义:不再需要两个枚举,所有NBT类型都统一在Tag中处理
  2. 天然支持嵌套:elements是[Tag]类型,而Tag可以是list,直接实现[[Int],[Double]]这类嵌套场景
  3. 符合规范要求:通过elementType明确列表的元素类型,读写时可直接据此校验、序列化/反序列化
  4. 兼容重复存储场景:比如[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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 01:35:15