变量
本章学习 Solidity
变量的相关知识,包括变量命名、变量类型等。
变量是指可以保存数据的内部存储单元,里面的数据可以在程序运行时引用或者修改。
变量都有一个名字,称为变量名。变量名是由字母、数字或下划线“_”组成的字符串,但不能包含空格或其它的特殊字符,也不能以数字开头。比如正确的变量名: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
的变量没有 undefined 或 null 等空值的概念。