【从0学习Solidity】 5. 变量数据存储和作用域 storage/memory/calldata

news2025/1/16 15:43:18

【从0学习Solidity】 5. 变量数据存储和作用域 storage/memory/calldata

在这里插入图片描述

  • 博主简介:不写代码没饭吃,一名全栈领域的创作者,专注于研究互联网产品的解决方案和技术。熟悉云原生、微服务架构,分享一些项目实战经验以及前沿技术的见解。
  • 关注我们的主页,探索全栈开发,期待与您一起在移动开发的世界中,不断进步和创造!
  • 本文收录于 不写代码没饭吃 的学习汇报系列,大家有兴趣的可以看一看。
  • 欢迎访问我们的微信公众号:不写代码没饭吃,获取更多精彩内容、实用技巧、行业资讯等。您关注的是我们前进的动力!

Solidity中的引用类型

引用类型(Reference Type):包括数组(array)和结构体(struct),由于这类变量比较复杂,占用存储空间大,我们在使用时必须要声明数据存储的位置。

数据位置

solidity数据存储位置有三类:storagememorycalldata。不同存储位置的gas成本不同。storage类型的数据存在链上,类似计算机的硬盘,消耗gas多;memorycalldata类型的临时存在内存里,消耗gas少。大致用法:

  1. storage:合约里的状态变量默认都是storage,存储在链上。

  2. memory:函数里的参数和临时变量一般用memory,存储在内存中,不上链。

  3. calldata:和memory类似,存储在内存中,不上链。与memory的不同点在于calldata变量不能修改(immutable),一般用于函数的参数。例子:

    function fCalldata(uint[] calldata _x) public pure returns(uint[] calldata){
        //参数为calldata数组,不能被修改
        // _x[0] = 0 //这样修改会报错
        return(_x);
    }

Example:
在这里插入图片描述

数据位置和赋值规则

在不同存储类型相互赋值时候,有时会产生独立的副本(修改新变量不会影响原变量),有时会产生引用(修改新变量会影响原变量)。规则如下:

  • 赋值本质上是创建引用指向本体,因此修改本体或者是引用,变化可以被同步:

    • storage(合约的状态变量)赋值给本地storage(函数里的)时候,会创建引用,改变新变量会影响原变量。例子:
    uint[] x = [1,2,3]; // 状态变量:数组 x
    
    function fStorage() public{
      //声明一个storage的变量 xStorage,指向x。修改xStorage也会影响x
      uint[] storage xStorage = x;
      xStorage[0] = 100;
    }
    

    Example:
    在这里插入图片描述

    • memory赋值给memory,会创建引用,改变新变量会影响原变量。

    • 其他情况下,赋值创建的是本体的副本,即对二者之一的修改,并不会同步到另一方

变量的作用域

Solidity中变量按作用域划分有三种,分别是状态变量(state variable),局部变量(local variable)和全局变量(global variable)

1. 状态变量

状态变量是数据存储在链上的变量,所有合约内函数都可以访问
gas消耗高。状态变量在合约内、函数外声明:

contract Variables {
    uint public x = 1;
    uint public y;
    string public z;
}

我们可以在函数里更改状态变量的值:

    function foo() external{
        // 可以在函数里更改状态变量的值
        x = 5;
        y = 2;
        z = "0xAA";
    }

2. 局部变量

局部变量是仅在函数执行过程中有效的变量,函数退出后,变量无效。局部变量的数据存储在内存里,不上链,gas低。局部变量在函数内声明:

    function bar() external pure returns(uint){
        uint xx = 1;
        uint yy = 3;
        uint zz = xx + yy;
        return(zz);
    }

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

Example:
在这里插入图片描述

4. 全局变量-以太单位与时间单位

以太单位

Solidity中不存在小数点,以0代替为小数点,来确保交易的精确度,并且防止精度的损失,利用以太单位可以避免误算的问题,方便程序员在合约中处理货币交易。

  • wei: 1
  • gwei: 1e9 = 1000000000
  • ether: 1e18 = 1000000000000000000
    function weiUnit() external pure returns(uint) {
        assert(1 wei == 1e0);
        assert(1 wei == 1);
        return 1 wei;
    }

    function gweiUnit() external pure returns(uint) {
        assert(1 gwei == 1e9);
        assert(1 gwei == 1000000000);
        return 1 gwei;
    }

    function etherUnit() external pure returns(uint) {
        assert(1 ether == 1e18);
        assert(1 ether == 1000000000000000000);
        return 1 ether;
    }

Example:
在这里插入图片描述

时间单位

可以在合约中规定一个操作必须在一周内完成,或者某个事件在一个月后发生。这样就能让合约的执行可以更加精确,不会因为技术上的误差而影响合约的结果。因此,时间单位在Solidity中是一个重要的概念,有助于提高合约的可读性和可维护性。

  • seconds: 1
  • minutes: 60 seconds = 60
  • hours: 60 minutes = 3600
  • days: 24 hours = 86400
  • weeks: 7 days = 604800
    function secondsUnit() external pure returns(uint) {
        assert(1 seconds == 1);
        return 1 seconds;
    }

    function minutesUnit() external pure returns(uint) {
        assert(1 minutes == 60);
        assert(1 minutes == 60 seconds);
        return 1 minutes;
    }

    function hoursUnit() external pure returns(uint) {
        assert(1 hours == 3600);
        assert(1 hours == 60 minutes);
        return 1 hours;
    }

    function daysUnit() external pure returns(uint) {
        assert(1 days == 86400);
        assert(1 days == 24 hours);
        return 1 days;
    }

    function weeksUnit() external pure returns(uint) {
        assert(1 weeks == 604800);
        assert(1 weeks == 7 days);
        return 1 weeks;
    }

Example:
在这里插入图片描述

总结

在这一讲,我们介绍了solidity中的引用类型,数据位置和变量的作用域。重点是storage, memorycalldata三个关键字的用法。他们出现的原因是为了节省链上有限的存储空间和降低gas。下一讲我们会介绍引用类型中的数组。

在这里插入图片描述

如果这份博客对大家有帮助,希望各位给作者一个免费的点赞👍作为鼓励,并评论收藏一下⭐,谢谢大家!!!
制作不易,如果大家有什么疑问或给作者的意见,欢迎评论区留言。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1031586.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机遇到MSVCP140.dll丢失问题?全面分析解决方案

随着科技的飞速发展,计算机已经成为人们日常生活和工作中不可或缺的工具。在计算机的使用过程中,有时会出现丢失 MSVCP140.dll 的问题,给用户带来了诸多不便。那么,什么是 MSVCP140.dll?为什么会出现丢失 MSVCP140.dll…

建议收藏《Verilog代码规范笔记_华为》(附下载)

华为verilog编程规范是坊间流传出来华为内部的资料,其贴合实际工作需要,是非常宝贵的资料,希望大家善存。至于其介绍,在此不再赘述,大家可看下图详细了解,感兴趣的可私信领取《Verilog代码规范笔记_华为》。…

批量调整视频饱和度和色度,提升你的视频剪辑效率!

作为一名视频剪辑师,你是否经常为如何高效地调整多个视频的饱和度和色度而烦恼?现在,我们为你提供了一种简单、快速、准确的方法,帮助你轻松解决这个问题! 首先我们要进入好简单批量智剪,并在左侧的板块栏…

MySQL详细案例 1:MySQL主从复制与读写分离

文章目录 1. MySQL主从复制1.1 使用场景1.2 MySQL的复制类型1.3 主从复制的工作过程1.4 实现MySQL主从复制1.4.1 前置准备1.4.2 主服务器mysql配置1.4.3 从服务器1 mysql配置1.4.3 从服务器2 mysql配置1.4.4 测试 1.5 主从复制的3种同步模式1.5.1 异步复制(Asynchro…

如何自动获取短信验证码?

点击下方关注我,然后右上角点击...“设为星标”,就能第一时间收到更新推送啦~~~ 这篇文章通过解决实际项目开发中遇到的如何自动获取短信验证码的问题,进一步讲述在Java中如何使用正则。 Java中如何使用正则 Java中正则相关类位于java.util.r…

分享从零开始学习网络设备配置--任务3.5 使用静态路由实现网络连通

任务描述 某公司规模较小,该公司的网络管理员经过考虑,决定在公司的路由器、交换机与运营商路由器之间使用静态路由,实现网络的互连。 静态路由一般适用于比较简单的网络环境。在这样的环境中,网络管理员应非常清楚地了解网络…

[C++随笔录] vector模拟实现

vector模拟实现 基本结构天选之子构造拷贝构造析构operator 空间reserveresizesize && capacity 增insertpush_back 删erasepop_back 查 && 改swapoperator[] 源码 基本结构 // 可以是不同类型, 用类模板 template <class T> class vector { public:// 源…

Spring学习笔记1 启示录

写段代码,引出Spring的好处 创建个空工程,然后在工程里建模块 可能是IEAD版本问题,每次建新的空工程,都需要退出重进 设置下maven和Encoding 新建模块 持久层接口 持久层实现类 业务层接口 业务层实现类 控制层(表现层) 建个测试类测试 分析这个程序存在的问题 假设现在新需…

git和github的入门操作

之前因为工作中用的都是SVN版本控制工具&#xff0c;没接触过git和github&#xff0c;现在开始深入自学Django框架技术后&#xff0c;看到官网推荐使用git&#xff0c;然后这两天网上查阅了很多文章教程&#xff0c;学到入门操作需要学习的点&#xff0c;太多的知识点要后面慢慢…

PostgreSQL 数据库实现公网远程连接

文章目录 前言1. 安装postgreSQL2. 本地连接postgreSQL3. Windows 安装 cpolar4. 配置postgreSQL公网地址5. 公网postgreSQL访问6. 固定连接公网地址7. postgreSQL固定地址连接测试 前言 PostgreSQL是一个功能非常强大的关系型数据库管理系统&#xff08;RDBMS&#xff09;,下…

有没有免费的云渲染平台?哪家云渲染平台收费更合理?

&#xfeff;如今&#xff0c;越来越多的设计师开始使用云渲染平台来加快渲染速度并降低成本。许多人都想知道是否有免费的云渲染平台&#xff0c;或者说哪家云渲染平台收费更合理。在本文中&#xff0c;小编将详细介绍这些问题&#xff0c;帮助您更好地了解和选择适合您需求的…

同一份数据全域共享,HashData UnionStore实时性背后的故事

时至今日&#xff0c;数据已经被越来越多的企业视为发展的战略资源&#xff0c;而云数仓则是数据发挥重要价值的关键媒介。云数仓的出现&#xff0c;不仅改变了传统数据仓库的服务模式&#xff0c;更给用户带来了应对海量、新型数据的存储和处理能力&#xff0c;为满足业务现代…

MES管理系统在生产中的应用及智能工厂的构建思路

在当今制造业中&#xff0c;随着信息化技术和智能化的不断发展&#xff0c;MES生产管理系统已成为工厂生产的核心组成部分。MES管理系统不仅能够提高生产效率&#xff0c;还可以优化生产流程&#xff0c;提升产品质量。本文将详细介绍MES管理系统在工厂生产中的应用以及构建智能…

PowerShell切换多个java版本

安装jdk1.8 和 jdk17 下载jdk 前往 oracle官网下载 配置环境变量 变量名 CLASSPATH变量值 .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar效果图&#xff1a; 变量名&#xff08;jdk1.8同理&#xff09; JAVA_HOME17变量值 C:\Program Files\Java\jdk-17效果图&#xff1…

更快,更稳,更智能,科聪穿梭车(RGV)快速构建方案!

随着自动化物流发展&#xff0c;密集存储得到越来越广泛地应用&#xff0c;已经是现代物流的重要组成部分之一。作为密集存储系统中关键设备之一&#xff0c;穿梭车&#xff08;RGV&#xff09;越来越受到大家的重视。 穿梭车&#xff08;RGV&#xff09;是一种智能机器人&…

GB28181协议-SDP详解

SDP协议 SDP全称是Session Description Protocol&#xff0c;翻译过来就是描述会话的协议。主要用于两个会话实体之间的媒体协商。 SDP描述由许多文本行组成&#xff0c;文本行的格式为<类型><值>&#xff0c;表示为keyvalue; SIP负责建立和释放会话&#xff0c…

基于vue3 + ant-design 自定义SVG图标iconfont的解决方案;ant-design加载本地iconfont.js不显示图标问题

基于vue3 ant-design 自定义SVG图标iconfont的解决方案&#xff1b; ant-design加载本地iconfont.js不显示图标问题 一、准备工作 1、首先去阿里巴巴矢量图标库自定义添加自己的图标&#xff1b;网站地址https://www.iconfont.cn/ 整个步骤是&#xff1a;选择图标–添加到项…

人大女王大学金融硕士——人生的每一刻,都是在为自己的明天铺垫

随着社会经济的迅速发展&#xff0c;经济全球化不断扩大。许多学子想要体验到更加多元化的教育&#xff0c;却又不想出国&#xff0c;那么中外合作办学硕士便是最好的方式。作为金融人士的你&#xff0c;不妨看看中国人民大学与加拿大女王大学合办的金融硕士项目&#xff0c;或…

【Verilog教程】3.2 Verilog 时延

关键词&#xff1a;时延&#xff0c; 惯性时延 连续赋值延时语句中的延时&#xff0c;用于控制任意操作数发生变化到语句左端赋予新值之间的时间延时。 时延一般是不可综合的。 寄存器的时延也是可以控制的&#xff0c;这部分在时序控制里加以说明。 连续赋值时延一般可分为…

人源化抗体的改造方式及其优势

抗体是一类能与抗原特异性结合的免疫球蛋白&#xff0c;作为免疫系统中的重要组成部分&#xff0c;在许多疾病的预防和治疗中发挥着重要作用。抗体治疗的最早应用可以追溯到中国人接种“人痘”预防天花的记载算起&#xff0c;国际上一般公认的人痘接种术最早起源于中国公元10世…