变量

本章学习 Solidity 变量的相关知识,包括变量命名、变量类型等。

视频Bilibili  |  Youtube
官网binschool.app
推特@BinSchool    DiscordBinDAO   微信:bkra50 

变量是指可以保存数据的内部存储单元,里面的数据可以在程序运行时引用或者修改。

变量都有一个名字,称为变量名。变量名是由字母、数字或下划线“_”组成的字符串,但不能包含空格或其它的特殊字符,也不能以数字开头。比如正确的变量名:symbol、totalSupply、_name、amount1 等等。

Solidity 是一种静态类型的编程语言,它要求在变量声明时,必须明确指定变量的类型。

变量声明时,如果没有赋给初值,都会有一个基于其类型的默认值,比如 int 类型的默认值为 0。

Solidity 提供了 3 种类型的变量:状态变量局部变量全局变量

1. 状态变量

状态变量是指在智能合约中声明的持久化存储的变量。它存在于合约的整个生命周期,直到合约被销毁。

状态变量的变动是要记录在区块链上的,永久存储,也就是通常所说的“数据上链”。

状态变量在合约的不同函数之间共享,可以通过调用函数来读取或修改它的数据值。

状态变量类似于其它编程语言中“类”的成员变量。

Solidity 中,状态变量通常在合约的顶层进行声明,并且定义在全部函数之外。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract StatusVar {
   uint256 myStatus = 1;  // 声明状态变量

   function getStatus() public view returns(uint256) {
      return myStatus;   // 使用状态变量
   }
}

这里首先声明了一个状态变量 myStatus,然后在函数 getStatus 中,把它作为函数的返回值。

运行合约,调用函数 getStatus,输出结果:

0: uint256: 1

2. 局部变量

局部变量是指在函数内部声明的变量,其作用域仅限于该函数内部。

局部变量的生命周期仅限于该函数的执行过程中,函数执行完毕后,局部变量将被销毁,它的值也将无法使用。

局部变量与状态变量的区别在于:状态变量的数据是要上链的,而局部变量不上链。

声明局部变量的语法与状态变量类似,只是要在函数的内部进行声明。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract LocalVar {
   function sum() public pure returns(uint256){
      uint256 a = 1;  // 声明局部变量 a
      uint256 b = 2;  // 声明局部变量 b
      uint256 result = a + b; // 声明局部变量 result,并使用局部变量a, b
      return result; // 使用局部变量 result 作为返回值
   }
}

运行合约,调用函数 sum,输出结果:

0: uint256: 3

3. 全局变量

全局变量是指在合约的顶层预先定义的特殊变量,用于提供有关区块链和交易属性的信息。

全局变量是由 Solidity 语言本身提供,用户无权定义或者修改,但可以直接在任何位置使用。

例如,常用的全局变量有:当前区块的时间戳 block.timestamp、区块高度 block.number、函数调用者地址 msg.sender 等。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract GlobalVar {
   // 返回当前函数调用所在的区块号、时间戳、调用者地址
   function getGlobalVars() public view returns(uint,uint,address){
     return (block.number, block.timestamp, msg.sender);
   }
}

运行以上合约,调用函数 getGlobalVars,输出下面的结果:

常用的全局变量:

名称 返回
blockhash(uint blockNumber) returns (bytes32) 指定区块的哈希值 
block.coinbase (address payable) 当前区块的矿工地址
block.difficulty (uint) 当前区块的难度值
block.gaslimit (uint) 当前区块的gaslimit
block.number (uint) 当前区块的区块号
block.timestamp (uint) 当前区块的时间戳
gasleft() returns (uint256) 当前剩余的gas
msg.data (bytes calldata) 完成 calldata
msg.sender (address payable) 消息发送者的地址,也就是函数调用者的地址
msg.sig (bytes4) 消息的函数签名,也就是calldata的前四个字节
msg.value (uint) 消息携带的token数量,也就是函数调用时,同时存入的token量
tx.gasprice (uint) 交易的gas价格
tx.origin (address payable) 交易的发送方地址

4. 注意问题

在声明变量时,应该需要注意以下问题:

  • 变量名规范的写法是采用小驼峰形式:每个单词的首字母大写,但整体以小写字母或者下划线“_”开头。比如:symbol、totalSupply、_name。
  • 变量名不应该以数字开头,必须以字母或下划线开头。例如:123test 是一个无效的变量名,但是  _123test 是一个有效的变量名。
  • 变量名是区分大小写的。例如:Name 和 name 是两个不同的变量。
  • 变量声明时,如果没有赋给初值,它就会有一个基于其类型的默认值,比如 int 类型变量的默认值为 0。
  • Solidity 的变量没有 undefinednull 等空值的概念。