美文网首页
8. Solidity:构造函数、函数修改器、常量

8. Solidity:构造函数、函数修改器、常量

作者: 泡泡龙吐泡泡 | 来源:发表于2023-09-27 09:21 被阅读0次

8.1 构造函数

构造函数(constructor)是一种比较特殊的函数,它在合约部署的时候被调用一次,之后不会再被调用。构造函数一般用于初始化一些变量。在Solidity 0.4.22之前,构造函数为合约名同名函数;Solidity 0.4.22之后,构造函数统一使用constructor作为函数名,例如,在构造函数中初始化合约owner:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

contract ConstructorDemo {
    // 定义合约拥有者变量
    address public owner;

    // 构造函数,只在合约部署时调用一次
    constructor() {
        // 在构造函数中初始化合约拥有者
        owner = msg.sender;
    }
}

8.2 函数修改器

函数修改器是一种实现重复代码简化的语法。形式上分为基本类型、带参数的类型、三明治类型。

8.2.1 基本函数修改器

如果我们要实现可暂停合约,那么需要有一个合约是否暂停的状态变量pauesd:

    // 合约暂停变量
    bool public paused;

同时,需要有一个设置合约暂停的函数:


    // 设置合约暂停、开启函数
    function setPaused(bool _paused) external {
        paused = _paused;
    }

在所有业务函数中,都需要对paused变量进行判断,以确定合约是否暂停。此时,可以使用函数修改器进行代码简化,并提高代码可读性。

函数修改器定义代码:

    // 函数修改器的定义
    modifier notPaused() {
        require(!paused, "Contract is Paused!");
        _;  // 代表使用该函数修改器的函数的其他代码在此处运行
    }

使用该函数修改器的函数,只能在函数未暂停时可用,否则会抛出异常。函数修改器中的_;代表使用该函数修改器的函数的其他代码在此处运行。

完整的实现代码:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

contract ModifierDemo {
    // 合约暂停变量
    bool public paused;
    // 计数变量
    uint256 public count;

    // 函数修改器的定义
    modifier notPaused() {
        require(!paused, "Contract is Paused!");
        _;  // 代表使用该函数修改器的其他代码在此处运行
    }

    // 设置合约暂停、开启函数
    function setPaused(bool _paused) external {
        paused = _paused;
    }

    // 计数器加一,在合约非暂停状态可用。使用函数修改器notPaused
    function inc() external notPaused {
        count += 1;
    }

    // 计数器减一,在合约非暂停状态可用。使用函数修改器notPaused
    function dec() external notPaused {
        count -= 1;
    }
}

只需要在需要使用函数修改器的函数定义中添加函数修改器的名称,就可以实现函数修改器的功能。

8.2.2 带参数的函数修改器

函数修改器可以带参数,使用方法和基本类型的函数修改器类似:

    modifier cap(uint _x) {
        require(_x<100, "x can not >=100");
        _;
    }

    function incBy(uint _x) external notPaused cap(_x) {
        count += _x;
    }

8.2.3 三明治函数修改器

通过改变_;的位置,可以实现三明治类型的函数修改器,使用三明治类型的函数修改器的函数代码运行顺序为:

  1. 运行函数修改器;
  2. 运行函数代码;
  3. 运行函数修改器;
    示例:
    modifier sandwich() {
        count += 2;
        _;
        count *= 2;
    }

    function foo() external notPaused sandwich {
        count *= 3;
    }

上述示例中,如果count为初始值0,则count变化顺序为:

  1. count + 2 = 2;
  2. count * 3 = 6;
  3. count * 2 =12;

即count最终值为12。

8.3 常量

当合约中的变量有固定值,这些值不允许在合约部署之后被任何的函数修改,就可以将其定义为常量,比如:合约拥有者地址。定义为常量的变量可以节省gas fee。

8.3.1 constant

constant变量必须在声明的时候初始化,之后再也不能改变。尝试改变的话,编译不通过。constant声明和初始化方式如下:

contract ConstantDemo {
    address public constant MY_ADDRESS = 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2;
}

contract VarDemo {
    address public MY_ADDRESS = 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2;
}

在上述示例中,MY_ADDRESS在ConstantDemo合约中声明为constant变量,在VarDemo合约中声明为变量,通过对两个值进行读取,发现消耗的gas fee(Cost only applies when called by a contract)相差较大:

  • constant变量读取消耗gas fee:356 gas
  • 变量读取消耗gas fee:2489 gas

注意:读取gas fee只有在读取者为合约时才会收取。

8.3.1 immutable

immutable变量可以在声明时、构造函数中进行初始化,因此更加灵活。immutable变量只能被赋值(初始化)一次。例如:

contract ImmutableDemo {
    address public immutable MY_ADDRESS;

    constructor() {
        // 在构造函数中初始化immutable变量
        MY_ADDRESS = _getMyAddress();
    }
    function _getMyAddress() view internal returns(address)  {
        return msg.sender;
    }
}

注意:经过测试,读取immutable变量消耗的gas fee和constant变量相同,均为356 gas。读取gas fee只有在读取者为合约时才会收取。

相关文章

网友评论

      本文标题:8. Solidity:构造函数、函数修改器、常量

      本文链接:https://www.haomeiwen.com/subject/gohcbdtx.html