solidity基础 -- 存储类型

news2025/1/23 8:30:07

        在Solidity智能合约开发中,存储类型是一个至关重要的概念。它不仅影响合约的性能,还决定了数据的存储位置和生命周期。Solidity提供了三种主要的存储类型:storagememorycalldata。本文将结合给定的代码示例,并通过更多实例详细介绍 这三种储存类型的区别。

  • storage:用于合约状态变量,数据持久保存在区块链上,对其修改会影响合约的长期状态。
  • memory:用于局部变量,仅在函数执行期间存在,函数结束后数据消失,可修改,但不会影响 storage 中的数据。
  • calldata:专门用于函数参数,是只读的,存储在调用数据中,在函数执行期间不可变。

 

1. Storage:状态变量与持久化存储

        storage是Solidity中最持久的存储类型,它用于存储合约的状态变量。这些变量会永久存储在区块链上,直到被显式修改或删除。storage变量的生命周期与合约的生命周期相同,这意味着它们在合约部署后一直存在。

        在我们的示例合约中,myStructs是一个storage类型的映射,它存储了每个地址对应的MyStruct结构体。当我们通过myStructs[msg.sender]访问或修改它时,实际上是在操作区块链上的持久化数据。

myStructs[msg.sender] = MyStruct({foo: 123, text: "bar"});

        这行代码将一个MyStruct实例存储到myStructs映射中,它会永久保存在区块链上,直到被覆盖或删除。

使用场景

  • 存储合约的状态变量,如用户余额、配置参数等。

  • 在函数中引用和修改状态变量。

注意事项

  • storage变量的读写操作成本较高,因为它们需要与区块链交互。

  • 修改storage变量会消耗更多的Gas。

2. Memory:临时存储与局部变量

        memory是Solidity中用于临时存储数据的存储类型。它用于存储函数内部的局部变量,这些变量仅在函数执行期间存在,函数执行结束后,存储在memory中的数据会被销毁。

        在示例合约中,readOnly是一个memory类型的变量,它是myStructs[msg.sender]的一个副本。对readOnly的修改不会影响原始的storage变量:

MyStruct memory readOnly = myStructs[msg.sender];
readOnly.foo = 456;

这行代码将myStructs[msg.sender]的内容复制到memory中,并修改了副本的foo属性。然而,这个修改不会反映到链上的storage变量中。

使用场景

  • 存储函数内部的临时变量。

  • 创建数据的副本进行操作,而不影响原始数据。

注意事项

  • memory变量的生命周期仅限于函数执行期间。

  • 创建memory变量需要消耗Gas,但比storage操作更高效。

3. Calldata:函数参数的只读存储

        calldata是Solidity中一种特殊的存储类型,它用于存储函数的输入参数。calldata变量是只读的,不能被修改。它们存储在内存中,但与memory不同,calldata变量不能被分配或重新赋值。

在示例合约中,yscalldata类型的参数:

function examples(uint[] calldata y, string calldata s) external returns (uint[] memory)

这行代码声明了两个calldata参数。y是一个uint数组,s是一个字符串。这些参数在函数调用时由调用者提供,并且在函数内部只能被读取,不能被修改。

使用场景

  • 存储函数的输入参数。

  • 用于传递大量数据,如数组或结构体,而不需要复制到memory

注意事项

  • calldata变量是只读的,不能被修改。

  • calldata变量不能被分配或重新赋值。

 

4.示例合约:DataLocations

在我们开始之前,先来看一个简单的Solidity合约,它展示了这三种存储类型的使用:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract DataLocations {
    struct MyStruct {
        uint foo;
        string text;
    }

    mapping (address => MyStruct) public myStructs;

    function examples(uint[] calldata y, string calldata s) external returns (uint[] memory) {
        myStructs[msg.sender] = MyStruct({foo: 123, text: "bar"});
        
        MyStruct storage myStruct = myStructs[msg.sender];
        myStruct.text = "foo";
        // 修改存储在`storage`中的状态变量

        MyStruct memory readOnly = myStructs[msg.sender];
        readOnly.foo = 456;
        // 修改存储在`memory`中的副本,不影响链上数据

        _internal(y);

        uint[] memory memArr = new uint[](3);
        memArr[0] = 234;
        return memArr;
    }

    function _internal(uint[] calldata y) private {
        uint x = y[0];
    }
}

其他实例:深入理解存储类型

为了进一步理解这三种存储类型的区别,我们再来看一个简单的示例合约:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract StorageTypes {
    uint public storageVar = 10; // 存储在`storage`中的状态变量

    function example() public pure returns (uint memoryVar) {
        uint memory memoryVar = 20; // 存储在`memory`中的局部变量
        return memoryVar;
    }

    function example2(uint calldataVar) public pure returns (uint) {
        return calldataVar; // `calldata`变量,只读
    }
}

总结

  • storage:用于合约状态变量,数据持久保存在区块链上,对其修改会影响合约的长期状态。
  • memory:用于局部变量,仅在函数执行期间存在,函数结束后数据消失,可修改,但不会影响 storage 中的数据。
  • calldata:专门用于函数参数,是只读的,存储在调用数据中,在函数执行期间不可变。

        通过深入理解这三种储存类型的区别,开发者可以更好地优化智能合约的性能和资源使用,确保合约的正确性和稳定性。

 

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

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

相关文章

集成学习算法

集成学习算法 一、集成学习介绍 二、随机森林算法 1、Bootstrap随机抽样 2、Bagging 算法 3、训练算法 4、代码实现 三、Boosting 算法 AdaBoost 算法 1、强分类器与弱分类器 2、训练算法 3、代码实现 一、集成学习介绍 集成学习是通过多个模型的组合形成一个精度更…

算法6(力扣148)-排序链表

1、问题 给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。 2、采用例子 输入:head [4,2,1,3] 输出:[1,2,3,4] 3、实现思路 将链表拆分成节点,存入数组使用sort排序,再用reduce重建链接 4、具…

DNA结合之Motif_1:CNN

1,首先可以识别在KO前后的motif——》由CNN模型做出识别,看看这个有没有什么灵感 2,ZNF143等都可以使用来识别 3,暂时只使用单个peak文件,后期可以使用ENCODE中所有的对应的TF的peak文件 1,文件解压之后…

【unity游戏开发之InputSystem——02】InputAction的使用介绍(基于unity6开发介绍)

文章目录 一、InputAction简介1、InputAction是什么?2、示例 二、InputAction参数相关1、点击齿轮1.1 Actions 动作(1)动作类型(Action Type)(2)初始状态检查(Initial State Check&a…

机器学习 vs 深度学习

目录 一、机器学习 1、实现原理 2、实施方法 二、深度学习 1、与机器学习的联系与区别 2、神经网络的历史发展 3、神经网络的基本概念 一、机器学习 1、实现原理 训练(归纳)和预测(演绎) 归纳: 从具体案例中抽象一般规律…

Docker核心命令与Yocto项目的高效应用

随着软件开发逐渐向分布式和容器化方向演进,Docker 已成为主流的容器化技术之一。它通过标准化的环境配置、资源隔离和高效的部署流程,大幅提高了开发和构建效率。Yocto 项目作为嵌入式 Linux 系统构建工具,与 Docker 的结合进一步增强了开发…

Linux通过docker部署京东矩阵容器服务

获取激活码 将京东无线宝app升级到最新版,然后打开首页,点击号 选择添加容器矩阵,然后获取激活码 运行容器 read -p "请输入你的激活码: " ACTIVECODE;read -p "请输入宿主机的缓存路径: " src;docker rm -f cmatrix;docker run -d -it --name cmatrix …

vue视频流播放,支持多种视频格式,如rmvb、mkv

先将视频转码为ts ffmpeg -i C:\test\3.rmvb -codec: copy -start_number 0 -hls_time 10 -hls_list_size 0 -f hls C:\test\a\output.m3u8 后端配置接口 import org.springframework.core.io.Resource; import org.springframework.core.io.UrlResource; import org.spring…

【Solr分词器】

Solr分词器 一,什么是solr分词器? 前面已经提到过,Solr是一个高性能的全文检索服务,基于Apache Lucene的,Lucene是一个用Java编写的开源的信息检索库,为全文索引和搜索提供了基础功能。 在Solr中&#xf…

OS2.【Linux】基本命令入门(1)

目录 1.操作系统是什么? 2.好操作系统的衡量标准 3.操作系统的核心工作 4.在计算机上所有行为都会被转换为硬件行为 5.文件 6.简单介绍一些基本命令 1.clear 2.pwd 3.ls 1.ls -l 2.隐藏文件的创建 3.ls -al 4.ls -ld 5.ls -F(注意是大写) 4.cd 1.cd .. "…

LabVIEW处理复杂系统和数据处理

LabVIEW 是一个图形化编程平台,广泛应用于自动化控制、数据采集、信号处理、仪器控制等复杂系统的开发。它的图形化界面使得开发人员能够直观地设计系统和算法,尤其适合处理需要实时数据分析、高精度控制和复杂硬件集成的应用场景。LabVIEW 提供丰富的库…

激光雷达和相机早期融合

通过外参和内参的标定将激光雷达的点云投影到图像上。 • 传感器标定 首先需要对激光雷达和相机(用于获取 2D 图像)进行外参和内参标定。这是为了确定激光雷达坐标系和相机坐标系之间的转换关系,包括旋转和平移。通常采用棋盘格等标定工具&…

C++----STL(vector)

vector的介绍 vector的文档介绍:cplusplus.com/reference/vector/vector/ 1.基本概念 简单来说,vector是表示可以改变大小的数组的顺序容器。使用连续的存储位置来存储元素,因此可以通过常规指针的偏移量来高效访问。 2.内部机制 vector…

Airflow:BranchOperator实现动态分支控制流程

Airflow是用于编排复杂工作流的开源平台,支持在有向无环图(dag)中定义、调度和监控任务。其中一个关键特性是能够使用BranchOperator创建动态的、有条件的工作流。在这篇博文中,我们将探索BranchOperator,讨论它是如何…

rocketmq-MQClientInstance-单进程多生产者组多消费者组的实例模型

多生产者组多消费者组的思考 思考下。当一个client,订阅多个consumergroup、多个productgroup时。此时进程的线程模型是如何的? 之前文章有分析到。消费者组,是有多个线程去共同协作的。 假设订阅2个consumergroup, 线程数量是2倍…

nuxt3项目打包部署到服务器后配置端口号和开启https

nuxt3打包后的项目部署相对于一般vite打包的静态文件部署要稍微麻烦一些,还有一个主要的问题是开发环境配置的.env环境变量在打包后部署时获取不到,具体的解决方案可以参考我之前文章 nuxt3项目打包后获取.env设置的环境变量无效的解决办法。 这里使用的…

Class ‘com.xxx.xxx‘ not found in module ‘xxxx‘ 解决方法

目录 前言1. 问题所示2. 原理分析3. 解决方法前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF 1. 问题所示 启动项目的时候,出现如下Bug: Class ‘com.xxx.xxx‘ not found in module ‘xxxx‘截图如下: 2. 原理分析 Java 项目中引用的类未能被正…

ngrok同时配置多个内网穿透方法

一、概要 ngrok可以用来配置免费的内网穿透,启动后就可以用外网ip:端口访问到自己计算机的某个端口了。 可以用来从外网访问自己的测试页面(80、8080)、ftp文件传输(21)、远程桌面(3389)等。 …

OGG 19C 集成模式启用DDL复制

接Oracle19C PDB 环境下 OGG 搭建(PDB to PDB)_cdb架构 配置ogg-CSDN博客,给 pdb 环境 ogg 配置 DDL 功能。 一个报错 SYShfdb1> ddl_setup.sqlOracle GoldenGate DDL Replication setup scriptVerifying that current user has privile…

【计算机网络】- 应用层HTTP协议

目录 初识HTTP 什么是HTTP 版本 HTTPS 模型 HTTP抓包工具 为什么使用 抓包工具的下载 下载后的重要操作 Fiddler的使用 HTTP请求与响应的基本格式 HTTP请求基本格式​编辑 HTTP响应基本格式 协议格式总结❗️❗️❗️​编辑 HTTP 详解 认识 URL URL基本格式 …