3. Solidity:变量存储类型和作用域
2023-09-24 本文已影响0人
泡泡龙吐泡泡
3.1 变量存储类型
引用类型变量占空间大,赋值的时候直接传递地址(类似指针),在使用时必需声明数据存储位置。
Solidity中引用类型包括:数组(array)、结构体(struct)、映射(mapping)。
Solidity数据存储类型有三种:storage、memory、calldata。
存储类型 | 存储位置 | 消耗gas | 使用场景 |
---|---|---|---|
storage | 链上 | 多 | 状态变量 |
memory | 内存 | 少 | 函数参数、临时变量 |
calldata | 内存 | 少 | 函数参数(不可修改) |
calldata一般用于函数参数,但是是只读类型,不可修改:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract VarStorage {
// calldata
function fcalldata(uint[] calldata _x) pure external returns (uint) {
// calldata 为只读类型,不能修改
// _x[0] = 1; // 报错
return _x[0];
}
}
3.2 赋值规则
在不同存储类型相互赋值时候,有时会产生独立的副本(修改新变量不会影响原变量),有时会产生引用(修改新变量会影响原变量)。规则如下:
赋值形式 | 规则 |
---|---|
storage -> storage | 引用 |
storage -> memory | 副本 |
memory -> memory | 引用 |
memory -> storage | 副本 |
- 代码示例
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract V2VRule {
uint[] public x = [1,2,3];
// storage -> storage
function s2s() external {
uint[] storage y = x; // 创建引用
y[0] = 12; // 修改y会修改x
}
// storage -> memory
function s2m() external view{
uint[] memory y = x; // 创建副本
y[0] = 23; // 修改y不会修改x
}
// memory -> memory
function m2m() external pure returns (uint[3] memory) {
uint[3] memory x1 = [uint(1),2,3];
uint[3] memory y = x1; // 创建引用
y[0] = 34; // 修改y会修改x
return x1;
}
// memory -> storage
function m2s() external returns (uint[3] memory) {
uint[3] memory y = [uint(1),2,3];
x = y; // 创建副本
x[0] = 45; // 修改x不会修改y
return y;
}
}
3.3 变量作用域
3.3.1 状态变量
状态变量是数据存储在链上的变量,所有合约内函数都可以访问 ,gas消耗高。状态变量在合约内、函数外声明:
contract Variables {
uint public x = 1;
uint public y;
string public z;
}
3.3.2 局部变量
局部变量是仅在函数执行过程中有效的变量,函数退出后,变量无效。局部变量的数据存储在内存里,不上链,gas低。局部变量在函数内声明:
function bar() external pure returns(uint){
uint xx = 1;
uint yy = 3;
uint zz = xx + yy;
return(zz);
}
3.3.3 全局变量
全局变量是全局范围工作的变量,都是solidity预留关键字。他们可以在函数内不声明直接使用:
function global() external view returns(address, uint, bytes memory){
address sender = msg.sender;
uint blockNum = block.number;
bytes memory data = msg.data;
return(sender, blockNum, data);
}
在上面例子里,我们使用了3个常用的全局变量:msg.sender
, block.number
和msg.data
,他们分别代表请求发起地址,当前区块高度,和请求数据。下面是一些常用的全局变量,更完整的列表请看这个链接:
全局变量 | 类型 | 说明 |
---|---|---|
blockhash(uint blockNumber) | bytes32 | 给定区块的哈希值 – 只适用于256最近区块, 不包含当前区块。 |
block.coinbase | address payable | 当前区块矿工的地址 |
block.gaslimit | uint | 当前区块的gaslimit |
block.number | uint | 当前区块的number |
block. timestamp | uint | 当前区块的时间戳,为unix纪元以来的秒 |
gasleft() | uint256 | 剩余 gas |
msg. data | bytes calldata | 完整call data |
msg. sender | address payable | 消息发送者 (当前 caller) |
msg. sig | bytes4 | calldata的前四个字节 (function identifier) |
msg. value | uint | 当前交易发送的wei值 |