免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

Sway 枚举内存布局深度解析:tag 标记与变体联合存储原理

Sway 枚举内存布局深度解析:tag 标记与变体联合存储原理 Sway 枚举内存布局深度解析tag 标记与变体联合存储原理【免费下载链接】sway Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/sway导读本文深入讲解 Sway 语言中枚举enum又称和类型在内存中的真实存储方式Sway 编译器为每个枚举值附加一个 8 字节的 tag标签用于区分当前表示的是哪一个变体而 tag 之后预留的空间则等于所有变体中尺寸最大者。全文以 官方参考文档 的两个典型示例为骨架结合 示例源码 与 IR 层实现sway-ir/src/irtype.rs逐字节剖析读完你不仅能准确算出任意枚举的内存占用还能理解为什么单元变体与最大变体会占用同样空间这一 Sway 语言的重要特性。枚举内存布局的核心规则Sway 中的枚举是一种和类型sum type运行时必须能够区分当前存储的是哪一个变体。为此Sway 在枚举的内存表示上采用了带标签的联合tagged union这一经典策略tag 字段一个 1 字word即8 字节的标签记录当前枚举实例是第几个变体数据区紧随 tag 之后其大小不是当前变体的大小而是所有变体中尺寸最大的那一个。因此计算一个枚举类型内存大小的公式非常简单枚举内存大小 8 字节tag 最大变体的字节数这一规则的含义值得特别注意无论你实例化的是哪个变体该枚举值在内存中占用的空间都是相同的。即使用最小、甚至不携带任何数据的单元变体unit variant其实际占用也是最大变体的空间因为编译器在编译期无法预知运行时到底存哪个变体必须按最坏情况最大变体预留空间。从 Sway 的 IR中间表示实现可以印证这一设计。在 sway-ir/src/irtype.rs 中枚举类型被明确描述为Enums are at the moment represented as structs with two fields, first one being the tag and second the union of variants.即枚举在 IR 中被表示为一个包含两个字段的结构体第一个字段是 tag第二个字段是所有变体的联合union。IR 层正是通过结构体有两个字段、且第一个字段是整数类型、第二个字段是联合类型这一特征来识别枚举的见 irtype.rs。这一实现事实与文档8 字节 tag 最大变体空间的表述完全吻合。示例一u64 变体与单元变体内存 16 字节枚举定义第一个示例定义了一个包含两个变体的枚举T完整源码位于 docs/reference/src/code/misc/advanced-concepts/enum_advanced/src/lib.swpub enum T { a: u64, b: (), }其中变体a的类型是u64即 64 位无符号整数占用8 字节。关于u64等数值类型的语义可参考 内置数值类型文档变体b的类型是单元类型()不携带任何数据占用0 字节。内存大小计算最大变体是u648 字节因此枚举 T 的大小 8 字节tag 8 字节u64 16 字节实例化两个变体的实际占用文档强调了一个反直觉的事实无论实例化哪个变体占用都是 16 字节。实例化携带数据的变体T::a(42)示例代码见 lib.swfn u64_type_space() { let a T::a(42); }实例化不携带数据的单元变体T::b示例代码见 lib.swfn u64_unit_space() { let b T::b; }两者在内存中均占用16 字节8 字节 tag 8 字节 u64 数据区。对于T::b而言数据区虽然实际没有用到但空间依然被预留——这正是和类型按最大变体对齐的代价也是使用枚举时必须意识到的内存开销。示例二b256 变体与 u64 变体内存 40 字节枚举定义第二个示例的枚举K同样包含两个变体见 lib.swpub enum K { a: b256, b: u64, }这里引入了一个新类型b256Sway 中唯一的字节类型固定包含256 位即 32 字节的信息且被当作一个整体类型对待而非可迭代的字节数组参见 b256 内置类型文档。内存大小计算最大变体是b25632 字节因此枚举 K 的大小 8 字节tag 32 字节b256 40 字节实例化两个变体的实际占用实例化b256变体需要传入一个 256 位的十六进制字面量示例见 lib.swfn b256_type_space() { let a K::a(0x0000000000000000000000000000000000000000000000000000000000000000); }实例化u64变体示例见 lib.swfn b256_unit_space() { let b K::b(42); }与示例一完全一致两者均占用40 字节8 字节 tag 32 字节 b256 数据区。K::b(42)虽然只需要 8 字节存数据但因为枚举布局必须容纳最大的b256变体实际依然占据 40 字节。变体数量更多的枚举如何计算虽然两个示例都只包含两个变体但上述规则可以自然推广到任意数量变体的枚举枚举大小 8 字节tag max(所有变体的大小)无论枚举有几个变体tag 始终只有 1 个8 字节用于区分当前是第几个变体数据区始终只取最大变体的大小。因此在设计枚举时若某个变体携带超大类型如b256、大结构体或数组整个枚举的内存占用都会被抬高所有其他变体包括单元变体的实例化都会付出同样的空间成本。这是编写高效 Sway 智能合约时需要权衡的要点之一。验证与运行仓库为本文两个示例提供了完整的可运行工程位于 docs/reference/src/code/misc/advanced-concepts/enum_advanced其 Forc.toml 中声明了项目名为enum-advanced以 src/lib.sw 为入口并依赖仓库本地的std标准库[project] authors [Fuel Labs contactfuel.sh] entry lib.sw license Apache-2.0 name enum-advanced [dependencies] std { path ../../../../../../../sway-lib-std }你可以通过 Sway 官方构建工具forc对该示例进行编译检查forc build在仓库根目录执行forc build --path docs/reference/src/code/misc/advanced-concepts/enum_advanced即可验证该枚举定义与实例化代码能通过编译。若想进一步观察编译产物可使用forc build --print-ir或forc build --print-asm查看 IR 与汇编直观看到枚举被拆解为tag 联合的低层表示。小结Sway 枚举采用tagged union布局8 字节 tag 最大变体空间所有变体的实例化占用相同内存即使是不携带数据的单元变体u648 字节变体的枚举占用 16 字节b25632 字节变体的枚举占用 40 字节IR 层将枚举表示为tag整型字段 变体联合的双字段结构体irtype.rs与文档规则一一对应设计枚举时最大变体的尺寸决定整个枚举的空间成本应在合约开发中予以考量。延伸阅读本文讨论的是枚举的内存布局细节若需回顾枚举的语法、枚举套枚举、枚举嵌套结构体等基础用法可参阅 内置类型之枚举 及 examples/enums 下的配套示例。【免费下载链接】sway Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/sway创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表