跳转到内容

与 func 的兼容性

Tact 本身编译为 FunC,并将其所有实体直接映射到各种 FunC 和 TL-B 类型。

转换类型

Tact 中的 原始类型可直接映射到 FunC 中的类型。

复制变量的所有规则都是一样的。 所有关于复制变量的规则都是一样的。其中一个最大的不同是,在 Tact 中没有可见的突变(mutation)操作符,大多数 slice操作都是就地突变变量。

转换序列化

在 Tact 中,StructsMessages的序列化是自动进行的,不像 FunC 需要手动定义序列化逻辑。

Tact 的自动布局算法是贪婪的。 这意味着它会获取下一个变量,计算其大小,并尝试将其放入当前cell中。 如果不合适,它会创建一个新cell并继续。 自动布局的所有内部结构在分配前都会被扁平化。

除了 Address 以外,所有可选类型在 TL-B 中都序列化为 Maybe

没有对 Either 的支持,因为它没有定义在某些情况下序列化时应选择什么。

实例

// _ value1:int257 = SomeValue;
struct SomeValue {
value1: Int; // Default is 257 bits
}
// _ value1:int256 value2:uint32 = SomeValue;
struct SomeValue {
value1: Int as int256;
value2: Int as uint32;
}
// _ value1:bool value2:Maybe bool = SomeValue;
struct SomeValue {
value1: Bool;
value2: Bool?;
}
// _ cell:^cell = SomeValue;
struct SomeValue {
cell: Cell; // Always stored as a reference
}
// _ cell:^slice = SomeValue;
struct SomeValue {
cell: Slice; // Always stored as a reference
}
// _ value1:int256 value2:int256 value3:int256 ^[value4:int256] = SomeValue;
struct SomeValue {
value1: Int as int256;
value2: Int as int256;
value3: Int as int256;
value4: Int as int256;
}
// _ value1:int256 value2:int256 value3:int256 ^[value4:int256] flag:bool = SomeValue;
struct SomeValue {
value1: Int as int256;
value2: Int as int256;
value3: Int as int256;
flag: Bool; // Flag is written before value4 to avoid auto-layout to allocate it to the next cell
value4: Int as int256;
}
// _ value1:int256 value2:int256 value3:int256 ^[value4:int256 flag:bool] = SomeValue;
struct SomeValue {
value1: Int as int256;
value2: Int as int256;
value3: Int as int256;
value4: Int as int256;
flag: Bool;
}
// _ value1:int256 value2:^TailString value3:int256 = SomeValue;
struct SomeValue {
value1: Int as int256;
value2: String;
value3: Int as int256;
}

将收到的信息转换为 op 操作

Tact 会为每条接收到的键入信息生成一个唯一的 op,但它可以被覆盖。

下面是 FunC 中的代码

() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure {
;; incoming message code...
;; Receive MessageWithGeneratedOp message
if (op == 1180414602) {
;; code...
}
;; Receive MessageWithOverwrittenOP message
if (op == 291) {
;; code...
}
}

在 Tact 中变成了这样:

message MessageWithGeneratedOp {
amount: Int as uint32;
}
message(0x123) MessageWithOverwrittenOP {
amount: Int as uint32;
}
contract Contract {
// Contract Body...
receive(msg: MessageWithGeneratedOp) {
// code...
}
receive(msg: MessageWithOverwrittenOP) {
// code...
}
}

转换 get-methods

你可以用与 FunC 的 get 方法兼容的 Tact 来表达除 list-style-lists 以外的所有内容。

基本返回类型

如果一个 get 方法在 FunC 中返回一个基元,那么在 Tact 中也可以用同样的方法实现它。

下面是 FunC 中的代码

int seqno() method_id {
return 0;
}

在 Tact 中变成了这样:

get fun seqno(): Int {
return 0;
}

张量(Tensor)返回类型

在 FunC 中,张量类型 (int, int)(int, (int)) 是有区别的,但对于 TVM 来说没有区别,它们都表示两个整数的堆栈。

要转换从 FunC get 方法返回的张量,需要定义一个 Struct,它与张量的字段类型相同,顺序也相同。

下面是 FunC 中的代码

(int, slice, slice, cell) get_wallet_data() method_id {
return ...;
}

在 Tact 中变成了这样:

struct JettonWalletData {
balance: Int;
owner: Address;
master: Address;
walletCode: Cell;
}
contract JettonWallet {
get fun get_wallet_data(): JettonWalletData {
return ...;
}
}

元组(Tuple)返回类型

在 FunC 中,如果返回的是元组而不是张量,则需要遵循张量类型的流程,但要将 “get ”方法的返回类型定义为可选类型。

下面是 FunC 中的代码

[int, int] get_contract_state() method_id {
return ...;
}

在 Tact 中变成了这样:

struct ContractState {
valueA: Int;
valueB: Int;
}
contract StatefulContract {
get fun get_contract_state(): ContractState? {
return ...;
}
}

混合元组(tuple)和张量(tensor)返回类型

如果某些张量是元组,则需要像前面的步骤一样定义结构体,而元组必须定义为单独的 Struct

下面是 FunC 中的代码

(int, [int, int]) get_contract_state() method_id {
return ...;
}

在 Tact 中变成了这样:

struct ContractStateInner {
valueA: Int;
valueB: Int;
}
struct ContractState {
valueA: Int;
valueB: ContractStateInner;
}
contract StatefulContract {
get fun get_contract_state(): ContractState {
return ...;
}
}

参数映射

get方法参数的转换过程非常直接。 每个参数按原样映射为 FunC 的参数,每个元组映射为一个 Struct

下面是 FunC 中的代码

(int, [int, int]) get_contract_state(int arg1, [int,int] arg2) method_id {
return ...;
}

在 Tact 中变成了这样:

struct ContractStateArg2 {
valueA: Int;
valueB: Int;
}
struct ContractStateInner {
valueA: Int;
valueB: Int;
}
struct ContractState {
valueA: Int;
valueB: ContractStateInner;
}
contract StatefulContract {
get fun get_contract_state(arg1: Int, arg2: ContractStateArg2): ContractState {
return ContractState{
valueA: arg1,
valueB: ContractStateInner{
valueA: arg2.valueA,
valueB: arg2.valueB, // trailing comma is allowed
}, // trailing comma is allowed
};
}
}