---
title: 与 func 的兼容性
description: Tact 编译为 FunC，并将其所有实体直接映射到各种 FunC 和 TL-B 类型。
---

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

## 转换类型 {#convert-types}

Tact 中的 [原始类型](/zh-cn/book/types#primitive-types)可直接映射到 FunC 中的类型。

复制变量的所有规则都是一样的。 所有关于复制变量的规则都是一样的。其中一个最大的不同是，在 Tact 中没有可见的突变(mutation)操作符，大多数 [`slice{:tact}`](/zh-cn/book/cells#slices)操作都是就地突变变量。

## 转换序列化 {#convert-serialization}

在 Tact 中，[Structs](/zh-cn/book/structs-and-messages#structs)和[Messages](/zh-cn/book/structs-and-messages#messages)的序列化是自动进行的，不像 FunC 需要手动定义序列化逻辑。

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

除了 [`Address{:tact}`](/zh-cn/book/types#primitive-types) 以外，所有可选类型在 TL-B 中都序列化为 `Maybe`。

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

### 实例

```tact
// _ value1:int257 = SomeValue;
struct SomeValue {
    value1: Int; // Default is 257 bits
}
```

```tact
// _ value1:int256 value2:uint32 = SomeValue;
struct SomeValue {
    value1: Int as int256;
    value2: Int as uint32;
}
```

```tact
// _ value1:bool value2:Maybe bool = SomeValue;
struct SomeValue {
    value1: Bool;
    value2: Bool?;
}
```

```tact
// _ cell:^cell = SomeValue;
struct SomeValue {
    cell: Cell; // Always stored as a reference
}
```

```tact
// _ cell:^slice = SomeValue;
struct SomeValue {
    cell: Slice; // Always stored as a reference
}
```

```tact
// _ 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;
}
```

```tact
// _ 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;
}
```

```tact
// _ 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;
}
```

```tact
// _ value1:int256 value2:^TailString value3:int256 = SomeValue;
struct SomeValue {
    value1: Int as int256;
    value2: String;
    value3: Int as int256;
}
```

## 将收到的信息转换为 `op` 操作 {#convert-received-messages-to-op-operations}

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

下面是 FunC 中的代码

```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 中变成了这样：

```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 中的代码

```func
int seqno() method_id {
    return 0;
}
```

在 Tact 中变成了这样：

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

### 张量(Tensor)返回类型

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

要转换从 FunC `get` 方法返回的张量，需要定义一个 [Struct](/zh-cn/book/structs-and-messages#structs)，它与张量的字段类型相同，顺序也相同。

下面是 FunC 中的代码

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

在 Tact 中变成了这样：

```tact
struct JettonWalletData {
    balance: Int;
    owner: Address;
    master: Address;
    walletCode: Cell;
}

contract JettonWallet {
    get fun get_wallet_data(): JettonWalletData {
        return ...;
    }
}
```

### 元组(Tuple)返回类型

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

下面是 FunC 中的代码

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

在 Tact 中变成了这样：

```tact
struct ContractState {
    valueA: Int;
    valueB: Int;
}

contract StatefulContract {
    get fun get_contract_state(): ContractState? {
        return ...;
    }
}
```

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

如果某些张量是元组，则需要像前面的步骤一样定义结构体，而元组必须定义为单独的 [Struct](/zh-cn/book/structs-and-messages#structs)。

下面是 FunC 中的代码

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

在 Tact 中变成了这样：

```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](/zh-cn/book/structs-and-messages#structs)。

下面是 FunC 中的代码

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

在 Tact 中变成了这样：

```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
        };
    }
}
```
