关键字:constant,view,pure
constant、view、pure三个函数修饰词的作用是告诉编译器,函数不改变/不读取状态变量这样函数执行就可以不消耗gas了,因为不需要矿工来验证。
注:constant在0.5.0以后版本被移除,进而使用view或pure来代替。
constant:代表这个函数可以读取状态变量但是不能改(已经移除)
view:view修饰的函数作用和constant一样,该函数可以读取状态变量但是不能改
pure:代表函数不能改也不能读状态变量,否则编译通不过
例如:
contract constantViewPure(){
uint public balance;
constructor(){
balance = 10;
}
function getBalanceByConstant() public constant returns(uint){
balance += 10; //声明为constant,试图去改变状态变量的值,编译会报warning, 但是可以通过
return balance; // return 20, 但是!状态变量balance的值不会改变,仍然为10!
//v0.5.0以后报错,^0.4.0可以执行,有及warning提示
}
function getBalanceByView() public view returns(uint){
balance += 10; //view和constant效果一致,编译会报warning,但是可以通过
return balance; // return 20,但是!状态变量balance的值不会改变,仍然为10!
//v0.5.0以后报错,^0.4.0可以执行,有及warning提示
}
function getBalanceByPure() public pure returns(uint){
return balance; //编译报错!pure比constant和view都要严格,pure完全禁止读写状态变量!
}
function getBalanceByPure2() public pure returns(uint){
return 10; //可以执行
}
}
详细描述
constant状态变量
状态变量可以被声明为 constant。(支持的仅有值类型和字符串)
在这种情况下,只能使用那些在编译时有确定值的表达式来给它们赋值。
任何通过访问 storage,区块链数据(例如 now, this.balance 或者 block.number)
或执行数据( msg.gas ) 或对外部合约的调用来给它们赋值都是不允许的。在内存分配上有边界效应(side-effect)的表达式是允许的,但对其他内存对象产生边界效应的表达式则不行。
内建(built-in)函数 keccak256,sha256,ripemd160,ecrecover,addmod 和 mulmod 是允许的(即使他们确实会调用外部合约)编译器不会为这些变量预留存储,它们的每次出现都会被替换为相应的常量表达式
view 函数
可以将函数声明为 view 类型,这种情况下要保证不修改状态。
下面的语句被认为是修改状态:
- 修改状态变量。
- 产生事件。
- 创建其它合约。
- 使用 selfdestruct。
- 通过调用发送以太币。
- 调用任何没有标记为 view 或者 pure 的函数。
- 使用低级调用。
- 使用包含特定操作码的内联汇编。
Pure 函数
函数可以声明为 pure ,在这种情况下,承诺不读取或修改状态。
除了上面解释的状态修改语句列表之外,以下被认为是从状态中读取:
- 读取状态变量。
- 访问 this.balance 或者 <address>.balance。
- 访问 block,tx, msg 中任意成员 (除 msg.sig 和 msg.data 之外)。
- 调用任何未标记为 pure 的函数。
- 使用包含某些操作码的内联汇编。