局部变量(Local Variable)的范围仅限于它们被定义的函数,但 状态变量(State Variable) 可以有三种范围。 public - public 修饰的 状态变量(State Variable) 可以在内部以及通过消息进行访问,对于一个公共状态变量,会自动生成一个getter函数。
在前文我们讲过 Solidity 是一种静态类型的语言,这就意味着在声明变量前需先指定类型。
而 Solidity 对变量划分了以下三种作用域范围:
- 状态变量(State Variable):
该变量的值被永久地存放在合约存储中,合约内所有函数可访问,其Gas(燃料)消耗高。
- 局部变量(Local Variable):
函数体声明的变量,其值在该函数执行前都存在的变量。
- 全局变量(Global Variable):
存在于全局命名空间的特殊变量,提供有关区块链和交易属性的信息。
状态变量(State Variable)
其值被永久地存放在一个合约存储中。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract SolidityTest {
   uint storedData;      // 状态变量(State variable)
   //这是构造器函数
   constructor() public {
      storedData = 10;   // 使用 状态变量
   }
}
局部变量(Local Variable):
声明变量在函数体的变量,其值在函数执行前一直存在。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract SolidityTest {
   uint storedData; // 状态变量
   //构造器函数
   constructor() public {
      storedData = 10;   
   }
   //声明一个函数
   function getResult() public view returns(uint){
      uint a = 1; // 局部变量(local variable)
      uint b = 2;
      uint result = a + b;
      return result; //返回 局部变量
   }
}

我们做些小改动,让函数返回 状态变量,会是什么样的结果呢?
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract SolidityTest {
   uint storedData; // 状态变量
   //构造器函数
   constructor() public {
      storedData = 10;   
   }
   //声明一个函数
   function getResult() public view returns(uint){
      uint a = 1; // 局部变量(local variable)
      uint b = 2;
      uint result = a + b;
      return storedData; //返回 状态变量
   }
}

您可能也注意到,编译图标下有 2 个警告。


针对第一个警告,那是 Solidity 0.7 版本之后对 构造器 的 可见修饰忽略了,解决办法:便是删除它。
而 第二个 警告 便是声明过的变量没有使用,这点倒是和 golang 很像,但在 Solidity 中并没有那么严格,只是给出警告提示,还是可以编译的,在这里建议,去掉没使用的变量。
全局变量(Global Variable)
存在全局工作区的特俗变量,用于提供区块链和交易的属性。
| Name | Returns | 
|---|---|
| blockhash(uint blockNumber) returns (bytes32) | Hash of the given block - only works for 256 most recent, excluding current, blocks | 
| block.coinbase (address payable) | Current block miner’s address | 
| block.difficulty (uint) | Current block difficulty | 
| block.gaslimit (uint) | Current block gaslimit | 
| block.number (uint) | Current block number | 
| block.timestamp (uint) | Current block timestamp as seconds since unix epoch | 
| gasleft() returns (uint256) | Remaining gas | 
| msg.data (bytes calldata) | Complete calldata | 
| msg.sender (address payable) | Sender of the message (current caller) | 
| msg.sig (bytes4) | First four bytes of the calldata (function identifier) | 
| msg.value (uint) | Number of wei sent with the message | 
| now (uint) | Current block timestamp | 
| tx.gasprice (uint) | Gas price of the transaction | 
| tx.origin (address payable) | Sender of the transaction | 
- blockhash(uint blockNumber) returns (bytes32):指定区块的区块哈希 —— 仅可用于最新的 256 个区块且不包括当前区块,否则返回 0 。
- block.basefee(- uint): 当前区块的基础费用
- block.chainid(- uint): 当前链 id
- block.coinbase(- address): 挖出当前区块的矿工地址
- block.difficulty(- uint): 当前区块难度
- block.gaslimit(- uint): 当前区块 gas 限额
- block.number(- uint): 当前区块号
- block.timestamp(- uint): 自 unix epoch 起始当前区块以秒计的时间戳
- gasleft() returns (uint256):剩余的 gas
- msg.data(- bytes): 完整的 calldata
- msg.sender(- address): 消息发送者(当前调用)
- msg.sig(- bytes4): calldata 的前 4 字节(也就是函数标识符)
- msg.value(- uint): 随消息发送的 wei 的数量
- tx.gasprice(- uint): 交易的 gas 价格
- tx.origin(- address): 交易发起者(完全的调用链)
标识符
与众多编程语言一样,在您声明 Solidity 变量名称时,请不要使用 Solidity 保留关键字,如break、boolean变量名是无效的。
Solidity 标识符一样也是由字母、下划线和数字组成的,注意:不要以数字开头来命名变量名。
在 Solidity 中,标识符是区分大小写的,如:name和Name是两个不同的变量名哦!
变量作用范围
局部变量(Local Variable)的范围仅限于它们被定义的函数,但 状态变量(State Variable) 可以有三种范围。
public - public 修饰的 状态变量(State Variable) 可以在内部以及通过消息进行访问,对于一个公共状态变量,会自动生成一个getter函数。
internal: internal(内部) 修饰的 状态变量(State Variable) 只能在内部从当前的合约或从它派生的合约中访问。
private:private 修饰的 状态变量(State Variable)只能从当前的合同内部访问,其派生类不能访问。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract C {
   uint public data = 30;
   uint internal iData= 10;
   uint private pData = 5;
   function x() public returns (uint) {
      data = 3; // internal(内部)
      pData = 7;  //可以使用
      return data;
   }
}
contract Caller {
   C c = new C();
   function f() public view returns (uint) {
     //c.pData = 11;  报错  错误提示 变量不可见
      return c.data(); //external (外部)
   }
}
//合约 D 继承了合约 C  后续会讲到
contract D is C {
   function y() public returns (uint) {
      iData = 3; // internal (内部)
     // pData = 4;  报错 错误提示变量未定义
      return iData;
   }
   function getResult() public pure returns(uint){
      uint a = 1; // 局部变量(local variable)
      uint b = 2;
      uint result = a + b;
      return result; //状态变量(state variable)
   }
}



 2022-12-10 20:49:38 +0800 +0800
2022-12-10 20:49:38 +0800 +0800 2022-12-09 20:56:45 +0800 +0800
2022-12-09 20:56:45 +0800 +0800 2022-12-05 22:34:42 +0800 +0800
2022-12-05 22:34:42 +0800 +0800 2022-12-01 20:30:51 +0800 +0800
2022-12-01 20:30:51 +0800 +0800