在 Solidity 中,public、private、external 和 internal 是用于控制函数和状态变量可见性的关键字。它们决定了谁可以访问合约中的数据和函数。以下是详细的区别和适用场景:

1. public

  • 特点

    • 函数或变量可以被合约内部、继承合约以及**外部(包括其他合约和用户)**访问。

    • Solidity 会自动为 public 状态变量生成一个getter 函数,方便外部读取。

  • 适用场景

    • 任何需要对外公开的函数或变量。
  • 示例:

contract Example {
    uint256 public count; // 自动生成 getter 函数

    function increment() public {
        count += 1; // 任何人都可以调用
    }
}

2. private

  • 特点

    • 只能在当前合约内部访问,不能被继承合约或外部访问。

    • 适用于需要隐藏实现细节或保护敏感数据的场景。

  • 适用场景

    • 仅在当前合约中使用的辅助函数或数据。
  • 示例

contract Example {
    uint256 private secretNumber;

    function setSecret(uint256 _number) public {
        secretNumber = _number; // 内部设置
    }

    function getDoubleSecret() public view returns (uint256) {
        return secretNumber * 2; // 内部访问
    }
}

3. internal

  • 特点

    • 可以在当前合约内部继承合约中访问,但不能被外部访问。

    • 适用于共享逻辑和数据的合约继承场景。

  • 适用场景

    • 在继承关系中共享功能。
  • 示例

contract Parent {
    uint256 internal sharedData;

    function setSharedData(uint256 _data) internal {
        sharedData = _data;
    }
}

contract Child is Parent {
    function updateData(uint256 _newData) public {
        setSharedData(_newData); // 子合约可以访问
    }
}

4. external

  • 特点

    • 函数只能被合约外部调用,不能在合约内部直接调用(除非使用 this 关键字)。

    • 更适合接口和跨合约调用

    • 函数参数使用 calldata,从而节省 Gas。

  • 适用场景

    • 公开但仅用于外部调用的函数。
  • 示例

contract Example {
    function externalFunction() external view returns (string memory) {
        return "This is an external function";
    }

    function callExternal() public view returns (string memory) {
        return this.externalFunction(); // 需要通过 this 调用
    }
}


总结:

public、private、internal、external区别

完整示例:

pragma solidity ^0.8.0;

contract VisibilityExample {
    uint256 public publicNumber = 1;       // 任何人都可以读取
    uint256 private privateNumber = 2;     // 只能在本合约内使用
    uint256 internal internalNumber = 3;   // 当前合约及继承合约可访问

    // 公开函数
    function getPublicNumber() public view returns (uint256) {
        return publicNumber;
    }

    // 内部函数,仅合约内和继承合约可调用
    function setInternalNumber(uint256 _num) internal {
        internalNumber = _num;
    }

    // 私有函数,不能被继承和外部调用
    function setPrivateNumber(uint256 _num) private {
        privateNumber = _num;
    }

    // 外部函数,不能内部直接调用
    function externalFunction() external view returns (uint256) {
        return internalNumber;
    }

    function testVisibility() public view returns (uint256) {
        return internalNumber; // 可访问 internal 变量
    }
}

contract ChildContract is VisibilityExample {
    function updateInternal() public {
        setInternalNumber(10); // 可以调用父合约的 internal 函数
    }
}

最佳实践:

• public:用于需要对外公开访问的函数和变量。

• private:保护敏感逻辑,避免外部或继承合约访问。

• internal:在父子合约之间共享逻辑。

• external:为接口或跨合约交互设计的函数。

通过合理使用可见性修饰符,可以提高合约的安全性和效率。

Mirror文章信息

Mirror原文:查看原文

作者地址:0xc994Df6BD78b5e78D4E820A57d65b4EFd33bf936

内容类型:application/json

应用名称:MirrorXYZ

内容摘要:ptseYThUmALnxsmPoCPJEzwWl4SYL5xD14VLPrCUTxw

原始内容摘要:fyLQZjNZi1X2MUwE8diSGJovC7m4--jYFvLQ-SES0OQ

区块高度:1562220

发布时间:2024-12-06 01:59:31