【Solidity】修饰符

访问修饰符

  • private:表示仅能在合约内部访问;可用于函数、状态变量

  • internal:表示能在合约内部或继承合约内部访问;可用于函数、状态变量

  • public:表示能在任何地方访问;可用于函数、状态变量

  • external:表示仅能在合约外部访问;仅可用于函数(但内部可以通过 this.f() 来调用)

contract Demo {
    uint private privateVar = 1;
    uint internalVar = 2; // default internal
    uint public publicVar = 3;

    function privateFunc() private view returns (uint) {
        return privateVar;
    }

    function internalFunc() internal view returns (uint) {
        return internalVar;
    }

    function publicFunc() public view returns (uint) {
        return publicVar;
    }

    function externalFunc() external pure returns (uint) {
        return 4;
    }

    function testFuncInDemo() public view {
        privateVar + internalVar + publicVar;

        privateFunc();
        internalFunc();
        publicFunc();
        // externalFunc();
    }
}

contract ChildDemo is Demo {
    function testFuncInChild() public view {
        publicVar + internalVar + publicVar;

        // privateFunc();
        internalFunc();
        publicFunc();
        // externalFunc();
    }
}

contract ExternalDemo {
    Demo demo = new Demo(); // 通过 new 创建外部合约实例

    function testFuncInExternal() public view {
        demo.publicVar;

        // demo.privateFunc();
        // demo.internalFunc();
        demo.publicFunc();
        demo.externalFunc();
    }
}

在 Solidity 中,public 修饰的状态变量会自动生成 getter 函数,一般情况下 可以直接访问变量,但也有需要调用 getter 的情况:

contract Demo {
    uint public publicVar = 1;
}

contract ExternalDemo {
    Demo demo = new Demo(); // 通过 new 创建外部合约实例

    function testFunc() public view returns (uint) {
        demo.publicVar; // 直接访问
        return demo.publicVar(); // 通过 getter 访问
    }
}



函数修饰符

  • pure:表示函数既不读取也不修改合约的状态变量
  • view:表示函数会读取合约的状态变量,但不修改它们
contract Demo {
    uint public x = 10;

    function pureFunc(uint a, uint b) public pure returns (uint) {
        return a * b;
    }

    function viewFunc() public view returns (uint) {
        return x;
    }
}

对于会修改状态变量的函数,不需要函数修饰符:

contract Demo {
    uint public count;

    function increment() external {
        count++;
    }
}

pure 和 view 函数不改写链上状态,用户直接调用这些函数不需要支付 gas 。但需要注意,合约内部非 pure/view 函数调用 pure/view 函数时仍需支付 gas 。

在以太坊中,以下语句被视为修改链上状态:① 写入状态变量; ② 释放事件; ③ 创建其他合约; ④ 使用 self destruct; ⑤ 通过调用发送以太币; ⑥ 调用任何未标记 view 或 pure 的函数; ⑦ 使用低级调用(low-level calls); ⑧ 使用包含某些操作码的内联汇编。



状态变量修饰符

  • constant:表示变量会在 [声明时] 确定值,且之后不会再更新;仅可用于值类型、string、bytes
  • immutable:表示变量会在 [声明时] / [合约部署时 (优先级更高)] 确定值,且之后不会再更新;仅可用于值类型
contract Demo {
    uint public constant NUM = 100;
    address public immutable OWNER; // 0.8.21 之前需在声明时初始化

    constructor() {
        OWNER = msg.sender;
    }
}



本地变量修饰符

在函数中,可用 storage、memory、calldata 修饰引用类型数据。消耗的 gas:storage > memory > calldata 。

  • storage:表示此处操作的是数据地址;仅可用于变量
  • memory:表示此处操作的是数据副本;可用于变量、参数、返回值
  • calldata:表示数据只读,不可操作;仅可用于参数
contract Demo {
    struct Person {
        string name;
        uint age;
    }
    Person[] public persons;

    // calldata: 表示数据只读, 不可操作; 仅可用于参数
    function addPerson(string calldata _name, uint _age) public {
        persons.push(Person(_name, _age));
    }

    function getPerson(uint _index) public view returns (string memory, uint) {
        // memory: 表示此处操作的是数据副本; 可用于变量、参数、返回值
        return (persons[_index].name, persons[_index].age);
    }

    function updatePerson(uint _index, uint _age) public {
        // storage: 表示此处操作的是数据地址; 仅可用于变量
        Person storage person = persons[_index];
        person.age = _age;
    }
}

需要注意的是,memory 赋值 memory 时操作的也是数据地址:

contract Demo {
    function memoryCo(
        uint[] memory arr
    ) public pure returns (uint[] memory, uint[] memory) {
        uint[] memory newArr = arr;
        newArr[0] = 100;
        return (newArr, arr); // newArr 和 arr 都被修改了
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JS.Huang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值