Tact 支持许多专为智能合约使用而定制的 原始数据类型。 不过,使用单独的存储方式往往会变得繁琐,因此有 Structs 和 Messages可以将类型组合在一起。
结构
结构体可以定义包含多个不同类型字段的复杂数据类型。 它们还可以嵌套。
结构体还可以包含默认字段和定义[可选类型]字段(/book/optionals)。 如果您有很多字段,但又不想一直在 [new instances](#instantiate)中为它们指定通用值,那么这将非常有用。
结构体还可用作获取器或其他内部函数的返回值。 它们有效地允许单个获取器返回多个返回值。
请注意,结构声明中的最后一个分号 ;
是可选项,可以省略:
字段的顺序很重要,因为它与TL-B 模式 中的内存布局一致。 不过,与某些采用手动内存管理的语言不同,Tact 在字段之间没有任何填充。
信息
消息中可以包含 [结构体](#structs):
消息与 结构体几乎相同,唯一不同的是,消息在序列化时有一个 32 位整数头,包含唯一的数字 id,通常称为 opcode(操作码)。 这使得信息可以与 [接收者](/book/receive)一起使用,因为合约可以根据这个 id 区分不同类型的信息。
Tact 会为每个接收到的信息自动生成这些唯一 ID(操作码),但也可以手动覆盖:
这对于要处理特定智能合约的某些操作码(如 Jetton standard)的情况非常有用。 该合约能够处理的操作码简表为此处以 FunC 表示。 它们是智能合约的接口。
业务
实例化
创建 Struct 和 Message 实例类似于 function calls,但需要用大括号 {}
(大括号)代替小括号 ()
指定参数:
当分配给字段的变量或常量的名称与该字段的名称重合时,Tact 提供了一种方便的语法快捷方式,有时称为字段双关。 有了它,你就不必输入多余的内容:
转换为 Cell
, .toCell()
通过使用 .toCell()
扩展函数,可以将任意 Struct 或 Message 转换为 [单元格
][单元格] 类型:
从 Cell
或 Slice
获取,.fromCell()
和 .fromSlice()
无需通过一系列相关的 .loadSomething()
函数调用来手动解析 [Cell
][cell] 或 [Slice
][slice],而是可以使用 .fromCell()
和 .fromSlice()
扩展函数。这些扩展函数将所提供的 [Cell
][cell] 或 [Slice
][slice] 转换为所需的 Struct 或 Message。
这些扩展函数仅尝试根据 Struct 或 Message 的结构解析 [Cell
][cell] 或 [Slice
][slice]。如果布局不匹配,可能会抛出各种异常——确保用 try...catch
块封装代码,以防止意外结果。
转换法
只要通过 .toCell()
和 .fromCell()
函数在 [单元格
][单元格]/[切片
][切片] 和 结构体/消息 之间进行转换,以下规律就会成立:
- 对于任何 Struct/Message类型的实例,调用
.toCell()
,然后对结果应用Struct.fromCell()
(或Message.fromCell()
),就会得到原始实例的副本:
- 对于任何与给定 Struct/Message 具有相同 TL-B 布局的 [
单元格
][单元格],调用 Struct.fromCell()
(或 Message.fromCell()
),然后通过 .toCell()
将结果转换为 [Cell
][单元格],就会得到原始 [单元格
][单元格] 的副本: