Skip to content

类型概览

在 Tact 程序中,每个变量、项和值都有一个类型。它们可以是:

  • 基本类型
  • 复合类型

此外,许多这样的类型可以设置为可空。

基本类型

Tact 支持多种为智能合约使用量身定制的基本数据类型:

  • Int — Tact 中的所有数字都是 257 位有符号整数,但可以使用较小的表示形式来减少存储成本。
  • Bool — 经典的布尔类型,具有真(true)和假(false)两个值。
  • Address — TON 区块链中标准的智能合约地址。
  • Slice, Cell, Builder — TON 虚拟机的基础类型。
  • String — 在 TON 虚拟机中表示文本字符串。
  • StringBuilder — 一个辅助类型,允许你以节省gas费的方式连接字符串。

布尔值

基本类型 Bool 是经典的布尔类型,它只能包含两个值:true(真)和 false(假)。这对于布尔逻辑运算以及存储标志位非常方便。

在 Tact 中,不存在隐式类型转换,所以两个布尔值之间的加法(+)操作是不可能的。然而,许多比较运算符是可用的,例如:

  • && 用于逻辑与(AND),
  • || 用于逻辑或(OR),
  • ! 用于逻辑非(NOT),
  • ==!= 用于检查等值,
  • !! 用于非空断言。

将 bool 值持久化到状态中非常节省空间,因为它们只占用 1 位。在状态中存储 1000 个布尔值每年的成本大约是 0.00072 TON。

复合类型

使用单独的存储方式往往变得繁琐,因此有多种方式将多个基本类型组合在一起,创建复合类型:

  • 映射(Maps) —— 键与值的关联。
  • 结构体和消息(Structs and Messages) —— 带有类型字段的数据结构。
  • 可选类型(Optionals) —— 用于变量或结构体与消息字段的空值。

注意,虽然合约和特征(contracts and traits)也被视为 Tact 类型系统的一部分,但不能像结构体和消息那样传递它们。相反,可以使用 initOf 表达式获取给定合约的初始状态。

映射(maps)

类型 map<k, v>用作将类型为 k 的键与相应的类型为 v 的值关联的一种方式。

map<k, v> 的示例:

solidity
// 一个键和值都是 Int 类型的空映射
let mapExample: map<Int, Int> = emptyMap();

想要了解更多关于它们的信息,请访问专门的页面:映射(Maps)

结构体和消息(Structs and Messages)

结构体和消息是将多个基本类型组合成一个复合类型的两种主要方式。

结构体的示例:

solidity
struct Point {
    x: Int;
    y: Int;
}

消息实例:

solidity
// 消息的自定义数字 ID
message(0x11111111) SetValue {
    key: Int;
    value: Int?; // 可选,Int 或 null
    coins: Int as coins; // 序列化成 TL-B 类型
}

想要了解更多关于它们的信息,请访问专门的页面:结构体和消息

可选类型(Optionals)

所有基本类型以及结构体和消息都可以是可为空的,并且可以持有一个特殊的 null 值。

可选类型的示例:

solidity
let opt: Int? = null; // Int 或 null,显式赋值为 null

想要了解更多关于它们的信息,请访问专门的页面:可选类型

合约(contracts)

在 Tact 中,合约作为 TON 区块链智能合约的主要入口点。它们包含了一个 TON 合约的所有函数、获取器和接收器,以及更多内容。

合约的示例:

solidity
contract HelloWorld {
    // 持久状态变量
    counter: Int;
 
    // 构造函数 init(),在此初始化所有变量
    // 注意,从 Tact 1.3.0 开始,空的 init 函数将不再需要,
    // 参见:https://github.com/tact-lang/tact/pull/167
    init() {
        self.counter = 0;
    }
 
    // 内部消息接收器,响应字符串消息 "increment"
    receive("increment") {
        self.counter += 1;
    }
 
    // 带有返回类型 Int 的获取器函数
    get fun counter(): Int {
        return self.counter;
    }
}

阅读更多关于它们的信息,请访问专门的页面:合约

特征(traits)

Tact 不支持传统的类继承,而是引入了特征的概念,可以视为抽象合约(类似于流行的面向对象语言中的抽象类)。它们的结构与合约相同,但不能初始化持久状态变量,同时允许覆盖一些行为。

来自 @stdlib/ownable 的特征 Ownable 的示例:

solidity
trait Ownable {
    // 持久状态变量,不能在特征中初始化
    owner: Address;
 
    // 内部函数
    fun requireOwner() {
        nativeThrowUnless(132, context().sender == self.owner);
    }
 
    // 带有返回类型 Address 的获取器函数
    get fun owner(): Address {
        return self.owner;
    }
}

使用特征 Ownable 的合约:

solidity
contract Treasure with Ownable {
    // 必须在合约中定义的持久状态变量
    owner: Address;
 
    // 构造函数 init(),在此初始化所有变量
    init(owner: Address) {
        self.owner = owner;
    }
}