文章
Solidity中internal 和 external的区别
internal 和 external 是用于控制函数和状态变量可见性的关键字,它们之间的主要区别在于 谁可以调用或访问它们
在 Solidity 中,internal 和 external 是用于控制函数和状态变量可见性的关键字,它们之间的主要区别在于 谁可以调用或访问它们。
1. internal 关键字#
- 可见性:
internal函数和状态变量只能在当前合约内部被访问,或者被继承自当前合约的派生合约访问。它们不能直接从外部(例如,通过交易或DApp)调用。 - 调用方式:
- 在当前合约内部: 可以直接通过函数名调用,例如
myInternalFunction();。 - 在派生合约中: 派生合约可以直接调用继承的
internal函数。
- 在当前合约内部: 可以直接通过函数名调用,例如
- 用途: 通常用于定义辅助函数或状态变量,这些辅助功能只在合约的内部逻辑中需要,而不需要对外暴露。这有助于封装和代码组织。 示例:
pragma solidity ^0.8.0;
contract ParentContract {
uint internal internalNumber = 10;
function _calculateSum(uint a, uint b) internal pure returns (uint) {
return a + b;
}
function getInternalNumber() public view returns (uint) {
return internalNumber;
}
function useInternalFunction() public view returns (uint) {
return _calculateSum(5, 7); // 在内部调用 internal 函数
}
}
contract ChildContract is ParentContract {
function getSumFromParent(uint x, uint y) public view returns (uint) {
return _calculateSum(x, y); // 子合约可以调用父合约的 internal 函数
}
function getParentInternalNumber() public view returns (uint) {
return internalNumber; // 子合约可以访问父合约的 internal 状态变量
}
}
2. external 关键字#
- 可见性:
external函数只能从合约外部被调用。它们不能在合约内部直接通过函数名调用(但可以通过this.functionName()进行外部调用,这会产生一个实际的EVM消息调用,成本较高,通常不建议这样做)。 - 调用方式:
- 从外部账户或DApp:
external函数是合约对外接口的一部分,可以通过交易或DApp调用。 - 从其他合约: 其他合约可以通过合约地址和ABI接口调用
external函数。
- 从外部账户或DApp:
- 用途: 主要用于定义合约的公共接口,即那些需要被外部用户或DApp调用的函数。当函数只期望从外部调用,并且不涉及内部函数之间的频繁相互调用时,使用
external比public更节省Gas,特别是对于数组等复杂数据类型的参数。 示例:
pragma solidity ^0.8.0;
contract MyContract {
uint public counter;
function incrementCounterExternal() external {
counter++;
}
function getCounter() public view returns (uint) {
return counter;
}
// 尝试在内部直接调用 external 函数会报错:
// function internalCallExternal() internal {
// incrementCounterExternal(); // 编译错误!
// }
// 如果非要在内部调用 external 函数,需要使用 this.functionName()
function internalCallExternalViaThis() public {
this.incrementCounterExternal(); // 这会产生一个额外的EVM消息调用,消耗更多Gas
}
}
总结比较#
| **特性** | **internal** | **external** |
| **可访问性** | 当前合约内部和继承合约 | 只能从合约外部 |
| **内部调用** | 可以,直接通过函数名 | 不可以,除非使用 `this.functionName()` (不推荐) |
| **外部调用** | 不可以 | 可以 |
| **Gas 效率** | 通常用于内部逻辑,不产生额外Gas开销 | 对于大型数组参数,通常比 `public` 更节省Gas |
| **主要用途** | 合约内部辅助函数,状态变量的封装 | 合约的公共接口,供外部调用 |
选择建议:
- 如果你希望一个函数只能在合约内部被调用,或者被它的子合约调用,使用
internal。 - 如果你希望一个函数只能从合约外部被调用(例如,用户或DApp),并且不希望它被当前合约中的其他函数直接调用,那么使用
external。 - 如果你希望一个函数既能从外部调用,也能在合约内部直接调用,那么使用
public。public是internal和external的结合体。 在实际开发中,根据函数的实际需求选择合适的可见性修饰符,可以提高合约的安全性和Gas效率。