函数
在 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;}
虚拟和抽象函数
如果 traits 有 virtual
关键字,则可以使用 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 函数都有其 唯一 的关联函数选择器,它们是 位有符号整数标识符,通常称为 方法 ID。
getter 的方法 ID 是使用 CRC16 算法从其名称派生的,如下所示:(crc16(<function_name>) & 0xffff) | 0x10000
。此外,Tact 编译器有条件地保留一些方法 ID 用于支持的接口的 getter,即: 用于 supported_interfaces
, 用于 lazy_deployment_completed
,以及 用于 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 位有符号整数,因此可以使用从 到 以及从 到 的整数。- 1$.
此外,还有一些方法 ID 是为 Tact 编译器在编译过程中插入的获取器保留的,它们是 113617、115390 和 121275。