函数
FunC 程序本质上是一系列函数声明/定义和全局变量声明。本节涵盖了第一个主题。
任何函数声明或定义都以一个共同的模式开始,接下来有三种情况之一:
- 
单个 ;,表示函数已声明但尚未定义。它可能会在同一文件中的后面或在传递给 FunC 编译器的其他文件中定义。例如,int add(int x, int y);是一个名为 add类型为(int, int) -> int的函数的简单声明。
- 
汇编函数体定义。这是通过低层级 TVM 原语定义函数以便在 FunC 程序中后续使用的方法。例如, int add(int x, int y) asm "ADD";是同一个 add函数的汇编定义,类型为(int, int) -> int,将转换为 TVM 操作码ADD。
- 
常规块语句函数体定义。这是定义函数的常用方式。例如, int add(int x, int y) {
 return x + y;
 }是 add函数的常规定义。
函数声明
如前所述,任何函数声明或定义都以一个共同的模式开始。以下是该模式:
[<forall declarator>] <return_type> <function_name>(<comma_separated_function_args>) <specifiers>
其中 [ ... ] 对应于可选条目。
函数名
函数名可以是任何标识符,也可以以 . 或 ~ 符号开头。这些符号的含义在声明部分解释。
例如,udict_add_builder?、dict_set 和 ~dict_set 都是有效且不同的函数名。(它们在 stdlib.fc 中定义。)
特殊函数名
FunC(实际上是 Fift 汇编器)有几个预定义的保留函数名,具有预定义的id。
- main和- recv_internal的 id 为 0
- recv_external的 id 为 -1
- run_ticktock的 id 为 -2
每个程序必须有一个 id 为 0 的函数,即 main 或 recv_internal 函数。
run_ticktock 在特殊智能合约的 ticktock 交易中被调用。
接收内部消息
recv_internal 在智能合约接收到内部入站消息时被调用。
当 TVM 初始化 时,栈上有一些变量,通过在 recv_internal 中设置参数,我们使智能合约代码能够了解其中的一些变量。那些代码不知道的变量将永远躺在栈底,从未被触及。
因此,以下每个 recv_internal 声明都是正确的,但具有较少变量的声明将稍微节省一些gas(每个未使用的参数都会增加额外的 DROP 指令)
() recv_internal(int balance, int msg_value, cell in_msg_cell, slice in_msg) {}
() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) {}
() recv_internal(cell in_msg_cell, slice in_msg) {}
() recv_internal(slice in_msg) {}
接收外部消息
recv_external 用于入站外部消息。
返回类型
返回类型可以是类型部分中描述的任何原子或复合类型。例如,
int foo();
(int, int) foo'();
[int, int] foo''();
(int -> int) foo'''();
() foo''''();
都是有效的函数声明。
也允许类型推断。例如,
_ pyth(int m, int n) {
  return (m * m - n * n, 2 * m * n, m * m + n * n);
}
是 pyth 函数的有效定义,类型为 (int, int) -> (int, int, int),用于计算勾股数。
函数参数
函数参数由逗号分隔。以下是参数的有效声明方式:
- 普通声明:类型 + 名称。例如,int x是函数声明() foo(int x);中类型为int、名称为x的参数声明。
- 未使用的参数声明:只有类型。例如,
是类型为int first(int x, int) {
 return x;
 }(int, int) -> int的有效函数定义。
- 推断类型的参数声明:只有名称。例如,
是类型为int inc(x) {
 return x + 1;
 }int -> int的有效函数定义。x的int类型由类型检查器推断。
请注意,尽管函数可能看起来像是多个参数的函数,实际上它是一个单一张量类型参数的函数。要了解差异,请参阅函数应用。然而,参数张量的组成部分通常被称为函数参数。
函数调用
非修改方法
非修改函数支持使用 . 的简短函数调用形式
example(a);
a.example();
如果函数至少有一个参数,它可以作为非修改方法被调用。例如,store_uint 的类型为 (builder, int, int) -> builder(第二个参数是要存储的值,第三个是位长度)。begin_cell 是创建新构建器的函数。以下代码等效:
builder b = begin_cell();
b = store_uint(b, 239, 8);
builder b = begin_cell();
b = b.store_uint(239, 8);
因此,函数的第一个参数可以在函数名前传递给它,如果用 . 分隔。代码可以进一步简化:
builder b = begin_cell().store_uint(239, 8);