Solidity 访问权限

智能合约的访问权限共有 4 种类型: private、internal、public 和  external,本章节主要讲述它们之间的区别及应用。


1. 访问权限

1.1 private

private 函数和状态变量仅在当前合约中可以访问,在继承的合约内不可访问。

例如:

// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Manager {
    function count() private pure returns(uint){
        return 2;
    }
    function test() public pure returns(uint) {
        return count();
    }
}

合约内部函数 test() 调用 private 函数 count(),是可以访问的。

例如:

// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Employee {
    function count() private pure returns(uint){
        return 2;
    }
}

contract Manager is Employee {
    function test() public pure returns(uint) {        // error
        return count();
    }
}

继承合约 Manager 调用基类合约 Employee 的 private 函数 count(),就会出现编译错误。

1.2 internal

internal 函数和状态变量可以在当前合约或继承合约里调用。需要注意的是不能加前缀 this,前缀 this 是表示通过外部方式访问。

例如:

// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Manager {
    function count() internal pure returns(uint){
        return 2;
    }
    function test() public pure returns(uint) {
        return count();
    }
}

合约内部函数 test() 调用 internal 函数 count(),是可以访问的。

例如:

// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Employee {
    function count() private pure returns(uint){
        return 2;
    }
}

contract Manager is Employee {
    function test() public pure returns(uint) {
        return count();
    }
}

继承合约 Manager 调用基类合约 Employee 的 internal 函数 count(),也是可以访问的。

1.3 public

public 函数是合约接口的一部分,可以通过内部或者消息来进行调用。对于 public 类型的状态变量,会自动创建一个访问器。

例如:

// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Manager {
    function count() public pure returns(uint){
        return 2;
    }
    function test() public pure returns(uint) {
        return count();
    }
}

合约内部函数 test() 调用 public 函数 count(),是可以访问的。

例如:

// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Employee {
    function count() public pure returns(uint){
        return 2;
    }
}

contract Manager is Employee {
    function test() public pure returns(uint) {
        return count();
    }
}

继承合约 Manager 调用基类合约 Employee 的 public 函数 count(),也是可以访问的。

// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Employee {
    function count() public pure returns(uint){
        return 2;
    }
}

contract Manager {
        function test() public returns(uint) {
          Employee e = new Employee(); 
          return e.count();
    }
}

外部合约 Manager 可以调用合约 Employee 的 public 函数 count()。

1.4 external

外部函数是合约接口的一部分,所以我们可以从其它合约或通过交易来发起调用。一个外部函数 f,不能通过内部的方式来发起调用,如f()不可以调用,但可以通过this.f()。

外部函数在接收大的数组数据时更加有效。

例如:

// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Employee {
    function count() external pure returns(uint){
        return 2;
    }
}

contract Manager {
        function test() public returns(uint) {
          Employee e = new Employee(); 
          return e.count();
    }
}

外部合约 Manager 可以调用合约 Employee 的 public 函数 count()。

例如:

// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract Manager {
    function count() external pure returns(uint){
        return 2;
    }
    function test() public pure returns(uint) {
        return count();
    }
}

合约内部函数 test() 调用 public 函数 count(),是不可以访问的。

2. 默认状态

2.1 状态变量

状态变量在函数外部声明(类似于class的属性),并永久存储在以太坊区块链中,更具体地说存储在存储 Merkle Patricia 树中,这是形成帐户状态信息的一部分。

状态变量默认类型为 internal。internal 和 private 类型的变量不能被外部访问,而 public 变量能够被外部访问。

例如:

// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract HelloWorld{
   uint a;
   uint internal b;
   uint private c;
   uint public d;
}

a、b、c、d 均为状态变量。

变量类型为 public 时,会生成一个和变量名相同的带返回值的函数。

例如:

// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract HelloWorld{
   uint public d;
}

相当于:

// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract HelloWorld{
   uint public d;

   function d() constant returns(uint){
       return d;
   }
}

2.2 方法

合约中的方法默认为 public 类型。

// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract HelloWorld{
   function a() constant returns(uint){
       return 123;
   }
}

2.3 继承

子合约可以访问 public 和 internal,无法访问 private 类型。

下一章:Solidity 存储位置 memory,storage,calldata

引用类型在 Solidity 中数据有一个额外的属性:存储位置,可选项为 memory 和 storage。memory:存储在内存中,即分配、即使用,越过作用域则 ...