calldata memory storage 区别详细讲解

Solidity变量存储位置解析

首先明确一点 calldata memory storage 都是用来修饰饮用类型的。

强制指定的数据位置:
    •    外部函数(就是说使用external关键字的函数)的参数(不包括返回参数): calldata,效果跟 memory 差不多
    •    状态变量: storage
默认数据位置:
    •    函数参数(包括返回参数): memory
    •    所有其它局部变量: storage

Solidity变量的数据存储位置

现在让我们回到memory关键字。从0.5.0版本开始,所有的复杂类型必须 显式指定其存储的数据位置,有三种可选的数据位置:memory、storage 和calldata。

注意:唯一可以省略数据位置声明的是状态变量,因为状态变量始终保存 在账号的存储中。

storage/存储

  • 存储中的数据是永久存在的。存储是一个key/value库
  • 存储中的数据写入区块链,因此会修改状态,这也是存储使用成本高的原因。
  • 占用一个256位的槽需要消耗20000 gas
  • 修改一个已经使用的存储槽的值,需要消耗5000 gas
  • 当清零一个存储槽时,会返还一定数量的gas
  • 存储按256位的槽位分配,即使没有完全使用一个槽位,也需要支付其开销

memory/内存

  • 内存是一个字节数组,槽大小位256位(32字节)
  • 数据仅在函数执行期间存在,执行完毕后就被销毁
  • 读或写一个内存槽都会消耗3gas
  • 为了避免矿工的工作量过大,22个操作之后的单操作成本会上涨

calldata/调用数据

  • 调用数据是不可修改、非持久化的区域,用来保存函数参数,其行为类似于内存
  • 外部函数的参数必须使用calldata,但是也可用于其他变量
  • 调用数据避免了数据拷贝,并确保数据不被修改
  • 函数也可以返回使用calldata声明的数组和结果,但是不可能分配这些类型

Storage 变量是指永久存储在区块链中的变量。 Memory 变量则是临时的,当外部函数对某合约调用完成时,内存型变量即被移除。

状态变量(在函数之外声明的变量)默认为“storage”形式,并永久写入区块链;而在函数内部声明的变量默认是“memory”型的,它们函数调用结束后消失。

处理函数内的结构体和数组的时候需要指定数据的类型是 storage 还是 memory。

<think>首先,用户的问题是关于Solidity智能合约中的默认存储方式,具体是询问在memorycalldatastorage中,默认属于哪一种。用户还提到了区别,所以我需要清晰地解释这三种存储方式的区别。 回顾系统级指令: - 所有行内数学表达式用$...$格式。 - 独立公式用$$...$$并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 在引用的段落末尾添加引用标识,如[^1]。 - 回答结构清晰,逐步解决问题。 - 参考提供的引用内容。 提供的引用: - [^1]: 总结storagememorycalldata的重要性,强调根据需求选择以保证效率与安全性。 - [^2]: 解释三种存储位置:storage(链上,gas高),memorycalldata(内存,gas低)。大致用法。 - [^3]: 区别storage用于状态变量,持久化;memory用于局部变量和参数,临时;calldata用于函数参数和返回值,只读。 用户的问题:"我想询问智能合约中默认的存储方式属于memorycalldatastorage中的哪一种 请问solidity 智能合约 默认存储方式 memory calldata storage 区别" 核心问题: 1. 默认存储方式是什么? 2. 解释memorycalldatastorage区别。 在Solidity中: - **Storage**:用于合约的状态变量(state variables),这些变量存储在区块链上,持久化保存。 - **Memory**:用于函数的局部变量(local variables)和某些参数,数据临时存储在内存中,函数执行后消失。 - **Calldata**:用于函数的参数,特别是外部函数的参数,是只读的,不能修改。 默认存储方式:在Solidity智能合约中,合约的状态变量默认是**storage**类型。因为状态变量是合约的一部分,存储在区块链上。 例如,声明一个状态变量时,不需要指定存储位置,它自动是storage: ```solidity contract MyContract { uint public myVar; // 默认为storage } ``` 对于函数参数和局部变量,需要显式指定存储位置,如memorycalldata。 回答结构: 1. **直接回答默认存储方式**:默认是storage,因为状态变量是合约的核心。 2. **解释区别**:详细说明memorycalldatastorage区别,包括用途、gas成本、持久性等。 3. **添加引用**:在解释中自然地引用提供的引用内容。 4. **生成相关问题**:在最后添加相关问题。 使用中文回答。 确保行内数学表达式用$...$,但在这个主题中,可能不需要数学表达式,除非涉及计算。如果有,比如gas成本计算,但这里可能不必要。 独立公式:如果有,比如定义gas公式,但可能不适用。 生成相关问题:基于主题,如优化gas使用、常见错误等。 最终回答结构: - 开头直接回答问题。 - 逐步解释: - 默认存储方式。 - 三种存储方式的区别。 - 示例代码。 - 添加引用。 - 相关问题。</think>### Solidity智能合约中默认存储方式与区别 在Solidity智能合约中,**默认的存储方式是`storage`**。这是因为合约的状态变量(如全局变量)自动存储在区块链上,持久化保存,无需显式声明。例如: ```solidity contract MyContract { uint public myVar; // 默认为storage类型,存储在链上 } ``` 状态变量是合约的核心数据,它们默认使用`storage`位置,确保数据在交易间持久存在[^1]。 下面,我将逐步解释`memory`、`calldata`和`storage`的区别,帮助您清晰理解: #### 1. **存储位置与持久性** - **`storage`**:用于**合约状态变量**(如全局变量),数据永久存储在区块链上,类似计算机硬盘。修改`storage`数据会消耗较高gas(因为涉及链上写入)。例如: ```solidity uint[] public arr; // 状态变量,默认为storage ``` - **`memory`**:用于**函数局部变量和参数**,数据临时存储在内存中,仅在函数执行期间存在,函数结束后消失。gas成本低,适合临时操作。例如: ```solidity function process(uint[] memory input) public { uint[] memory temp = input; // 局部变量,使用memory } ``` - **`calldata`**:用于**函数参数(特别是外部函数)**,数据是只读的,不能被修改。通常用于处理外部调用传入的数据(如用户输入),gas成本最低。例如: ```solidity function readData(uint[] calldata data) external pure { // data是只读的,不能修改 } ``` #### 2. **Gas成本对比** - `storage`:操作成本最高,因为数据写入区块链。例如,修改一个状态变量可能消耗数千gas。 - `memory`和`calldata`:成本较低,数据仅在内存处理。gas消耗通常在几百范围内,适合高频操作。 - 数学表达:Gas成本可建模为$C_{\text{storage}} \gg C_{\text{memory}} \approx C_{\text{calldata}}$,其中$C$表示gas消耗[^2]。 #### 3. **关键区别总结** | 特性 | `storage` | `memory` | `calldata` | |------------|----------------------------|----------------------------|----------------------------| | **用途** | 状态变量(持久化数据) | 局部变量/参数(临时数据) | 函数参数(只读数据) | | **持久性** | 永久存储在链上 | 临时,函数结束消失 | 临时,只读 | | **可修改性**| 可读写 | 可读写 | 只读,不可修改 | | **Gas成本**| 高(链上存储) | 低(内存操作) | 最低(只读优化) | | **示例** | `uint public balance;` | `function add(uint a, uint b) memory` | `function get(uint[] calldata ids)` | #### 4. **常见错误与最佳实践** - **错误示例**:未指定存储位置导致高gas或错误。 ```solidity function badExample(uint[] input) public { // 错误:未指定存储位置,Solidity可能默认使用storage,导致意外高gas input[0] = 1; // 可能修改链上数据 } ``` 正确做法:显式声明为`memory`或`calldata`。 - **最佳实践**:根据场景选择: - 用`storage`保存关键状态(如用户余额)。 - 用`memory`处理临时计算(如数组排序)。 - 用`calldata`优化外部调用参数(节省gas)[^3]。 - 在Solidity中,正确选择存储位置是提升合约效率和避免安全漏洞的关键[^1]。 #### 5. **引用说明** - 总结起来,在Solidity编程语言中理解和正确地运用storagememorycalldata三种变量存储位置非常重要。它们各自有自己独特之处并适合处理不同场景下问题,在编写智能合约过程中我们必须根据实际需求来正确选取和运用它们以保证代码效率与安全性[^1]。 - Solidity数据存储位置有三类:storagememorycalldata。不同存储位置的gas成本不同。storage类型的数据存在链上,类似计算机的硬盘,消耗gas多;memorycalldata类型的临时存在内存里,消耗gas少[^2]。 - storage用于声明合约的状态变量,数据存储在合约的存储空间中,持久保存在区块链上。memory用于声明函数的局部变量和参数,数据仅在函数执行期间存在,不保存在区块链上。calldata用于存储函数参数和返回值,是只读的,不能被修改[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值