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.numbermsg.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值
上一篇 下一篇

猜你喜欢

热点阅读