合约函数

在本节中,我们将了解合约中可能遇到的不同类型的函数:

1.构造器(Constructors)

构造函数是一种特殊类型的函数,只在部署合约时运行一次,可用于初始化合约的状态。

    #[constructor]
    fn constructor(ref self: ContractState, owner: Person) {
        self.names.write(owner.address, owner.name);
        self.total_names.write(1);
        self.owner.write(owner);
    }

一些需要注意的重要规则:

1.您的合约不能有一个以上的构造函数。 2.您的构造函数必须命名为 constructor。 3.它必须使用 #[constructor] 属性标注。

2.公共函数

如前所述,公有函数可以从合约外部访问。它们必须定义在带有#[external(v0)]属性注解的实现块中。这个属性只影响可见性(public 或 private/internal),但并不影响这些函数修改合约状态的能力。

    #[external(v0)]
    impl NameRegistry of super::INameRegistry<ContractState> {
        fn store_name(ref self: ContractState, name: felt252, registration_type: RegistrationType) {
            let caller = get_caller_address();
            self._store_name(caller, name, registration_type);
        }

        fn get_name(self: @ContractState, address: ContractAddress) -> felt252 {
            let name = self.names.read(address);
            name
        }
        fn get_owner(self: @ContractState) -> Person {
            let owner = self.owner.read();
            owner
        }
    }

外部函数

外部函数是可以修改合约状态的函数。它们是公共的,可以被任何其他合约或外部调用。 外部函数是 public 函数,其中的 self:ContractState 以引用的形式通过关键字 ref 传递,使得你可以修改合约的状态。

        fn store_name(ref self: ContractState, name: felt252, registration_type: RegistrationType) {
            let caller = get_caller_address();
            self._store_name(caller, name, registration_type);
        }

视图函数

视图函数是只读函数,允许你访问合约中的数据,同时确保合约的状态不会被修改。它们可以被其他合约或外部调用。 视图函数是 public 函数,其中 self.ContractState 被作为快照传入,这会防止你修改合约的状态。

        fn get_name(self: @ContractState, address: ContractAddress) -> felt252 {
            let name = self.names.read(address);
            name
        }

注意: 外部函数和视图函数都是公共函数,这一点很重要。要在合约中创建内部函数,您需要在使用 #[external(v0)]属性标注的实现块之外定义它。

3.私有函数

未在注有#[external(v0)]属性的代码块中定义的函数是私有函数(也称为内部函数)。它们只能在合约内部调用。

    #[generate_trait]
    impl InternalFunctions of InternalFunctionsTrait {
        fn _store_name(
            ref self: ContractState,
            user: ContractAddress,
            name: felt252,
            registration_type: RegistrationType
        ) {
            let mut total_names = self.total_names.read();
            self.names.write(user, name);
            self.registration_type.write(user, registration_type);
            self.total_names.write(total_names + 1);
            self.emit(StoredName { user: user, name: name });

        }
    }

等等,这个#[generate_trait]属性是什么?这个实现的trait定义在哪里?嗯,#[generate_trait]属性是一个特殊的属性,它告诉编译器为实现块生成一个trait定义。这允许你摆脱为实现块定义trait和实现trait的模板代码。我们将在下一节中看到更多关于这方面的内容。

说到这里,您可能还在想,如果您不需要在您的函数(例如,辅助函数/库函数)中访问合约的状态,所有这些是否真的有必要。事实上,您也可以在实现块之外定义内部函数。我们 需要 在实现块内部定义函数的唯一原因是我们想要访问合约的状态。

    fn get_contract_name() -> felt252 {
        'Name Registry'
    }

    fn get_owner_storage_address(self: @ContractState) -> starknet::StorageBaseAddress {
        self.owner.address()
    }
Last change: 2023-08-10, commit: a3bc10b