Solidity:变量数据存储和作用域 storage/memory/calldata
Solidity中的引用类型
引用类型(Reference Type):包括数组(array)和结构体(struct),由于这类变量比较复杂,占用存储空间大,我们在使用时必须要声明数据存储的位置。
数据位置
Solidity数据存储位置有三类:storage,memory和calldata。不同存储位置的gas成本不同。storage类型的数据存在链上,类似计算机的硬盘,消耗gas多;memory和calldata类型的临时存在内存里,消耗gas少。大致用法:
-
storage:合约里的状态变量默认都是storage,存储在链上。 -
memory:函数里的参数和临时变量一般用memory,存储在内存中,不上链。尤其是如果返回数据类型是变长的情况下,必须加memory修饰,例如:string, bytes, array和自定义结构。 -
calldata:和memory类似,存储在内存中,不上链。与memory的不同点在于calldata变量不能修改(immutable),一般用于函数的参数。例子:function fCalldata(uint[] calldata _x) public pure returns(uint[] calldata){//参数为calldata数组,不能被修改// _x[0] = 0 //这样修改会报错return(_x); }数据位置和赋值规则
在不同存储类型相互赋值时候,有时会产生独立的副本(修改新变量不会影响原变量),有时会产生引用(修改新变量会影响原变量)。规则如下:
-
赋值本质上是创建引用指向本体,因此修改本体或者是引用,变化可以被同步:
storage(合约的状态变量)赋值给本地storage(函数里的)时候,会创建引用,改变新变量会影响原变量。例子:
uint[] x = [1,2,3]; // 状态变量:数组 xfunction fStorage() public{//声明一个storage的变量 xStorage,指向x。修改xStorage也会影响xuint[] storage xStorage = x;xStorage[0] = 100;
}
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.number和msg.data,他们分别代表请求发起地址,当前区块高度,和请求数据。下面是一些常用的全局变量,更完整的列表请看这个链接:
blockhash(uint blockNumber): (bytes32) 给定区块的哈希值 – 只适用于256最近区块, 不包含当前区块。block.coinbase: (address payable) 当前区块矿工的地址block.gaslimit: (uint) 当前区块的gaslimitblock.number: (uint) 当前区块的numberblock.timestamp: (uint) 当前区块的时间戳,为unix纪元以来的秒gasleft(): (uint256) 剩余 gasmsg.data: (bytes calldata) 完整call datamsg.sender: (address payable) 消息发送者 (当前 caller)msg.sig: (bytes4) calldata的前四个字节 (function identifier)msg.value: (uint) 当前交易发送的wei值block.blobbasefee: (uint) 当前区块的blob基础费用。这是Cancun升级新增的全局变量。blobhash(uint index): (bytes32) 返回跟当前交易关联的第index个blob的版本化哈希(第一个字节为版本号,当前为0x01,后面接KZG承诺的SHA256哈希的最后31个字节)。若当前交易不包含blob,则返回空字节。这是Cancun升级新增的全局变量。
4. 全局变量-以太单位与时间单位
以太单位
Solidity中不存在小数点,以0代替为小数点,来确保交易的精确度,并且防止精度的损失,利用以太单位可以避免误算的问题,方便程序员在合约中处理货币交易。
wei: 1gwei: 1e9 = 1000000000ether: 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;
}
时间单位
可以在合约中规定一个操作必须在一周内完成,或者某个事件在一个月后发生。这样就能让合约的执行可以更加精确,不会因为技术上的误差而影响合约的结果。因此,时间单位在Solidity中是一个重要的概念,有助于提高合约的可读性和可维护性。
seconds: 1minutes: 60 seconds = 60hours: 60 minutes = 3600days: 24 hours = 86400weeks: 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;
}
测试代码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;contract DataStorage {// The data location of x is storage.// This is the only place where the// data location can be omitted.uint[] public x = [1,2,3];function fStorage() public{//声明一个storage的变量xStorage,指向x。修改xStorage也会影响xuint[] storage xStorage = x;xStorage[0] = 100;}function fMemory() public view{//声明一个Memory的变量xMemory,复制x。修改xMemory不会影响xuint[] memory xMemory = x;xMemory[0] = 100;xMemory[1] = 200;uint[] memory xMemory2 = x;xMemory2[0] = 300;}function fCalldata(uint[] calldata _x) public pure returns(uint[] calldata){//参数为calldata数组,不能被修改// _x[0] = 0 //这样修改会报错return(_x);}
}contract Variables {uint public x = 1;uint public y;string public z;function foo() external{// 可以在函数里更改状态变量的值x = 5;y = 2;z = "0xAA";}function bar() external pure returns(uint){uint xx = 1;uint yy = 3;uint zz = xx + yy;return(zz);}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);}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;}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;}
}
相关文章:
Solidity:变量数据存储和作用域 storage/memory/calldata
Solidity中的引用类型 引用类型(Reference Type):包括数组(array)和结构体(struct),由于这类变量比较复杂,占用存储空间大,我们在使用时必须要声明数据存储的位置。 数据位置 …...
ElementUI中的el-table解决宽度问题 - 根据内容自动撑开
在使用element-ui中,会发现表格组件el-table在未指定宽度情况下,会自动计算并给表格宽度赋值。但实际开发中,有时需要根据内容实际长度自动撑开显示,由内容的多少而决定表格的宽度,而不是默认宽度为100%。在默认情况下…...
react apollo hooks
1、创建ApolloProvider来包装整个程序 <ApolloProvider client{client}><App /> <ApolloProvider> 2、useQuery查询 工作方式usequery将返回一个数组 const {要返回的对象} useQuery(传入参数) 实例 const query gqlquery name {whatever {field}} e…...
Android 10.0 SystemUI启动流程
1、手机开机后,Android系统首先会创建一个Zygote(核心进程)。 2、由Zygote启动SystemServer。 3、SystemServer会启动系统运行所需的众多核心服务和普通服务、以及一些应用及数据。例如:SystemUI 启动就是从 SystemServer 里启动的…...
洛谷 P1032 [NOIP2002 提高组] 字串变换
P1032 [NOIP2002 提高组] 字串变换 - 洛谷 | 计算机科学教育新生态 题目来源 洛谷 题目内容 [NOIP2002 提高组] 字串变换 题目背景 本题不保证存在靠谱的多项式复杂度的做法。测试数据非常的水,各种做法都可以通过,不代表算法正确。因此本题题目和…...
网络资源模板--Android Studio 外卖点餐App
目录 一、项目演示 二、项目测试环境 三、项目详情 四、完整的项目源码 原创外卖点餐:基于Android studio 实现外卖(点)订餐系统 非原创奶茶点餐:网络资源模板--基于 Android Studio 实现的奶茶点餐App报告 一、项目演示 网络资源模板--基于Android …...
【Linux】网络新手村
欢迎来到 破晓的历程的 博客 ⛺️不负时光,不负己✈️ 引言 今天,我们就开始学习Linux网络相关的内容。这篇博客作为Linux网络板块的第一篇博客看,我们首先要带着大家明白Linux网络的一些名词的概念,为之后的学习扫清障碍。然后我…...
123123
123123...
在pycharm中使用jupyter
在pycharm中使用jupyter 前置条件:你的环境中应该有juptyer ,没有的话 pip install jupyter 点击项目目录,右键->new->jupyter notebook 打开file settings 找到 jupyter server (按照默认的用代理服务器就行) P…...
MongoDB:掌握核心常用命令语句,精通数据操作
标题:MongoDB:掌握核心命令,精通数据操作 前言: MongoDB 是一种非关系型数据库,以文档为中心,使用 JSON 格式的 BSON 来存储数据。它具有高可用性、高性能和易于扩展的特点,被广泛应用于各种规模的项目中。本文将详细介绍 MongoDB 的常用命令,帮助你更好地理解和掌握…...
Redis中测试Stream的例子
当你想要测试 Redis 中的 Stream 功能时,可以通过 Redis 的命令行客户端或者使用任何支持 Redis 的编程语言来操作。下面我会给出一个简单的例子,使用 Redis 的命令行客户端 redis-cli 来测试 Stream 的基本功能。 准备工作 确保你已经安装并启动了 Re…...
28 H3C SecPath F1000 概览(主要功能是总 观看全局)
28 H3C SecPath F1000 概览(主要功能是总 观看全局) 特性简介 概览页面通过清晰的图形化模块清晰展示了设备关键数据信息及各类状态,并支持灵活排版布局,以便实时查看用户关心的数据。预定义监控默认展示了设备基础信息模块,也可以手动添加其…...
标准版视频检测终端功能有哪些? 捷顺高清视频车位引导系统怎么样?
随着城市化进程的加速,城市交通压力日益增大,停车难问题成为了许多城市居民的共同困扰。在这样的背景下,车位引导系统的出现,无疑为解决这一难题提供了一种有效的解决方案。车位引导系统利用先进的信息技术,通过实时监…...
说明本文档目录是软件开发梳理需求常见问题QA文档,方便客户看,也方便我们的售前人员,需求分析人员,ui设计师,原型绘图人员,思维导图绘图人员查看。
https://doc.youyacao.com/117/2150 说明 本文档目录是软件开发梳理需求常见问题QA文档,方便客户看,也方便我们的售前人员,需求分析人员,ui设计师,原型绘图人员,思维导图绘图人员查看。 提示 本内容客户…...
Echarts桑基图
关于Echarts的使用方法参考:vue2中echarts的使用_vue2中使用echarts-CSDN博客 实现效果: 代码: var sysT {"用采": #2D9BFF,"营销系统": #39BFFF,"ERP": #76C2FF,"财务管控": #5F57FC,"PMS&…...
wordpress网站添加一个临时维护功能
把以下代码放到functions.php文件中,主要用网站临时维护或者用于备案。事情做好了,把以下代码删除即可!!! 有时遇到一些情况,比如站点需要闭站备案、或者被要求停站等等,我们就可以使用本文的功…...
充电桩开源平台,开发流程有图有工具
慧哥充电桩开源平台产品研发流程是确保产品从概念阶段到市场推广阶段的有序进行的关键。以下是对您给出的步骤的详细解释和建议: 设计业务流程: 在这一步,团队需要确定产品的核心功能、目标用户以及如何满足用户需求。进行市场调研,了解竞争…...
数据中台设计书及建设指南(中台及大数据解决技术方案)
1. 中台概念 2. 推动企业组织模式演进 3. 建设方法 4 .中台内容 5. 数据安全体系 中台内容围绕数据中台建设评估、整体框架、数据采集,结构化、半结构化、非结构化的数据采集,数据计算能力、存储计算引擎、数据架构、数据挖掘、各种不同数据层建设、模型…...
合合信息大模型“加速器”重磅上线
大模型技术的发展和应用,预示着更加智能化、个性化未来的到来。如果将大模型比喻为正在疾驰的科技列车,语料便是珍贵的“燃料”。本次世界人工智能大会期间,合合信息为大模型打造的“加速器”解决方案备受关注。 在大模型训练的上游阶段&…...
# Sharding-JDBC 从入门到精通(10)- 综合案例(三)查询商品与测试及统计商品和总结
Sharding-JDBC 从入门到精通(10)- 综合案例(三)查询商品与测试及统计商品和总结 一、Sharding-JDBC 综合案例-查询商品-dao 1、查询商品:Dao 实现:在 ProductDao 中定义商品查询方法: //查询商…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...
