跳转到内容

函数

在 Tact 中,函数可以通过不同的方式定义:

  • 全局静态函数
  • 扩展函数
  • 可变函数
  • 原生函数
  • 接收器(Receiver)函数
  • 获取器(getter)函数

除了 接收器函数,所有函数的定义(参数列表)和调用(参数列表)都可以使用逗号:

fun foo(
a: Int, // trailing comma in parameter lists is allowed
) {}
fun bar() {
foo(
5, // trailing comma in argument lists is allowed too!
);
}

全局静态函数

您可以在程序的任何地方定义全局函数:

fun customPow(a: Int, c: Int): Int {
let res: Int = 1;
repeat(c) {
res *= a;
}
return res;
}

虚拟和抽象函数

如果 traitsvirtual 关键字,则可以使用 override 允许继承 traits 的合约修改内部函数。 函数也可以标记为 abstract,在这种情况下,继承合约必须定义其实现:

trait FilterTrait with Ownable {
// 此 trait 的用户可以重写虚拟函数
virtual fun filterMessage():Bool {
return sender() != self.owner;
}
abstract fun specialFilter():Bool;
}
带有 FilterTrait 的合约 Filter {
// 覆盖 FilterTrait 的默认行为
override fun filterMessage():Bool {
return true;
}
override fun specialFilter():Bool {
return true;
}
}

扩展函数

扩展函数允许你为任何可能的类型实现扩展。

警告 第一个参数的名称必须名为 self,该参数的类型必须是你要扩展的类型。

extends fun pow(self: Int, c: Int) {
let res: Int = 1;
repeat(c) {
res = res * self;
}
return res;
}

可变函数

可变函数是对值进行变更,将其替换为执行结果。 可变函数是对数值进行变异,用执行结果代替数值。 要执行突变,函数必须改变 self 值。

extends mutates fun customPow(self: Int, c: Int) {
let res: Int = 1;
repeat(c) {
res *= self;
}
self = res;
}

原生函数

原生函数是 FunC 函数的直接绑定:

原生函数也可以是可变函数和扩展函数。

@name(store_uint)
native storeUint(s: Builder, value: Int, bits: Int): Builder;
@name(load_int)
extends mutates native loadInt(self: Slice, l: Int): Int;

接收器函数

接收器函数是负责在合约中接收信息的特殊函数,只能在合约或trait中定义。

contract Treasure {
// This means that this contract can receive the comment "Increment" and this function would be called for such messages
receive("Increment") {
self.counter += 1;
}
}

获取器函数

获取器函数定义智能合约上的获取器,只能在合约或特征中定义。 Getter 函数不能用来读取其他合约的状态:如果您需要获取一些数据,您需要通过发送带有请求的消息和定义接收器来读取请求答案。

contract Treasure {
get fun counter(): Int {
return self.counter;
}
}

明确解决方法 ID 碰撞的问题

Available since Tact 1.6 (not released yet)

与 TON 合约中的其他函数一样,getter 函数都有其 唯一 的关联函数选择器,它们是 1919 位有符号整数标识符,通常称为 方法 ID

getter 的方法 ID 是使用 CRC16 算法从其名称派生的,如下所示:(crc16(<function_name>) & 0xffff) | 0x10000。此外,Tact 编译器有条件地保留一些方法 ID 用于支持的接口的 getter,即:113617113617 用于 supported_interfaces115390115390 用于 lazy_deployment_completed,以及 121275121275 用于 get_abi_ipfs

有时,不同名称的 getter 最终会得到相同的方法 ID。如果发生这种情况,您可以重命名某些 getter,或者手动指定方法 ID 作为编译时表达式,如下所示:

contract ManualMethodId {
const methodId: Int = 16384 + 42;
get(self.methodId) fun methodId1(): Int {
return self.methodId;
}
get(crc32("crc32") + 42 & 0x3ffff | 0x4000)
fun methodId2(): Int {
return 0;
}
}

请注意,_不能_使用 TVM 保留的方法 ID,也不能使用某些初始正整数,因为编译器会将其用作函数选择器。

用户指定的方法 ID 是 19 位有符号整数,因此可以使用从 218-2^{18}5-5 以及从 2142^{14}2182^{18} 的整数。- 1$.

此外,还有一些方法 ID 是为 Tact 编译器在编译过程中插入的获取器保留的,它们是 113617、115390 和 121275。