侧边栏壁纸
博主头像
秋码记录

一个游离于山间之上的Java爱好者 | A Java lover living in the mountains

  • 累计撰写 29 篇文章
  • 累计创建 40 个标签
  • 累计创建 185 个分类

玩以太坊链上项目的必备技能(变量作用域-Solidity之旅五)

局部变量(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; //返回 局部变量
   }
}

img

我们做些小改动,让函数返回 状态变量,会是什么样的结果呢?

// 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; //返回 状态变量
   }
}

img

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

img

img

针对第一个警告,那是 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 保留关键字,如breakboolean变量名是无效的。

Solidity 标识符一样也是由字母下划线数字组成的,注意:不要以数字开头来命名变量名。

在 Solidity 中,标识符是区分大小写的,如:nameName是两个不同的变量名哦!

变量作用范围

局部变量(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)
   }
}

img