solidity中datalocation数据位置

22 篇文章 0 订阅
2 篇文章 0 订阅

solidity中datalocation数据位置
1.memory:修饰的变量的数据存储在内存中;
2.storage:修饰的变量的数据将永久存储在区块链上。
3.calldata:一般只有在外部函数(external)的参数被强制指定为calldata,这种数据位置是只读的,不会持久化到区块链中。internal 接口中常常出现

interface IanimalEat{
      function eat(string calldata myname) external returns(string memory);
}

参考: https://blog.csdn.net/yuanziwoxin/article/details/85249384

值类型赋值,总是创建独立副本。
storage也称为引用传递:


1.在storage和 memory之间(或来自 calldata)的赋值总是创建一个独立的副本。

2.从 memory到 memory的赋值仅创建引用。这意味着对一个内存变量的更改在引用相同数据的所有其他内存变量中同样有效。

3.从storage到本地storage变量的赋值也仅赋值一个引用。

函数中 uint[] y = x; 默认是storage
函数参数,uint[] memoryArray 默认是引用位置

pragma solidity ^0.4.0;

contract TestLoc {
    uint[] x; //  x的存储位置是storage

    // memoryArray的存储位置是 memory
    function f(uint[] memoryArray) public returns (uint[]) {
        x = memoryArray;    // 从 memory 复制到 storage

        uint[] y = x;          // storage 引用传递局部变量y(y 是一个 storage 引用)
        y[1] = 2;               // x y 都会被修改

        // 错误, 不能将memory赋值给局部变量
        // y = memoryArray;

        g(x);               // 引用传递, g可以改变x的内容
        h(x);               // 拷贝到memory, h无法改变x的内容
        return x;
    }

    function g(uint[] storage storageArray) internal {
        storageArray[2] = 3;
    }

    function h(uint[] memoryArray) public {
        memoryArray[2] = 4;
    }
}

所有其他到storage的赋值总是被复制。这种情况的示例是赋值给状态变量或storage结构体类型的局部变量成员,即使局部变量本身只是一个引用。

// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.7.0;

contract DataLocationTest {
    
    uint[] stateVar = [1,4,5];
    
    function foo() public{
        // case 1 : 从存储中加载到内存
        uint[] memory y = stateVar; // 复制 stateVar 到 y
        
        // case 2 : from memory to storage
        y[0] = 12;
        y[1] = 20;
        y[2] = 24;
        
        stateVar = y; // copy the content of y to stateVar
        
        // case 3 : from storage to storage
        uint[] storage z = stateVar; // z is a pointer to stateVar
        
        z[0] = 38;
        z[1] = 89;
        z[2] = 72;
    }
    
}

在remix,debug下测试上面代码
在这里插入图片描述
要单步执行(Step over)代码,请单击上图红色框中的箭头。

第一种情况:
从storage 到memory的赋值
你应该首先注意到,正如我们在EVM部分中提到的, 状态(Solidity State)部分加载了storage 的stateVar的内容,当然没有局部变量。

当你单步执行时,应该看到变量 y出现在局部变量(Solidity locals)部分中。继续执行(step over),你会注意到,为了分配必要的内存空间,需要使用很多字节码

并从 storage中加载每个字,然后将其复制到 memory中。这意味着要支付更多的 gas ,因此从 storage到 memory

第二种情况:
从memory到storage的赋值
让我们研究第二种情况:从memory到storage的赋值。

当你修改完存储在memory中的副本并且想要将更改保存回storage时,可以使用它。它同样消耗大量的 gas 。如果我们用调试器步骤详细信息中的剩余 gas (remaining gas)来计算 gas 差值,则为17,083 gas 。该操作使用了四个SSTORE操作码:第一个用于存储数组大小(保持不变,消耗800个 gas ),另外三个用于更新数组的值(每个消耗了5,000个 gas )。

第三种情况
从storage到storage的赋值
现在,让我们看一下情况三:从storage到storage的赋值。这次将创建一个新的局部变量,并包含与stateVar相同的内容。如果我们查看代码的执行过程,会注意到Solidity所做的,将包含数组长度的存储的第一个插槽地址入栈。根据文档,对于动态数组,插槽位置包含数组长度,用于计算包含数组数据的插槽位置。

来比较两者的 gas 成本:

第一种是将数据复制到memory,然后更新并复制回 storage, 使用21,629 gas ,

第二种是直接创建引用并更新状态, 使用 5,085 gas 。

那么很明显第二种方法是便宜得多。

但是,如果我们像这样直接更新状态变量呢,像这样:

stateVar[0] = 12;

也有可能但是,如果你要处理映射和嵌套数据类型(我们将在后面看到),则使用storage指针可以让代码更具可读性。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端段

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值