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 中定义商品查询方法: //查询商…...

RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...

.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...

(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...

人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...

【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...

WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...