深入理解Solidity 二

Solidity数据位置

  • 所有复杂的数据类型,即数组、结构和映射类型,都会有一个额外属性“数据位置”,用来指定数据的存储位置,即数据是存储在memory还是存储在storage里面
  • 根据上下文环境,IDE会自动指定数据的默认存储位置,但是也可以通过在类型名字之后添加关键字stirage或者memory进行修改
  • 函数参数(包括返回的参数)的数据位置默认是memory,局部变量的数据存储位置默认是storage,状态变量的数据位置强制是storage
  • 另外还有第三种数据存储位置,calldata,这个是一块只读的,不会永久存储的位置,用来存储函数的参数。外部函数的参数(非返回函数)的数据位置会被强制指定为calldata,效果和memory差不多。

数据位置总结

强制

  • 外部函数的参数(不包括返回的参数):calldata
  • 状态变量:storage默认存储位置

可变

  • 函数参数(包括返回参数):memory
  • 引用类型的局部变量:storage,例,动态数组使用哈希表,要求很大的存储空间,遍历key和value是可能的,防止哈希碰撞。
  • 值类型的局部变量:栈(stack)

特别要求

  • 公开可见(publicly visible)的函数参数一定是memory类型,如果要求是storage类型,则必须是private或者internal函数。这个的目的是为了防止公开调用占用资源。
  • memory和storage只要数据类型一致,就可以互相传数值。如果是memory传给storage,是对于数据的完整拷贝传过去,不是简简单单的引用。同样是storage,如果是状态变量就会改写原先内容,相当于拷贝,存储到永久性区间里面。如果是局部变量,不管对方是状态变量还是局部变量都是引用 

例子

  • 讲解
  • 类型之间都是storage,那么就是引用,如果类型不同,就是复制然后操作。uint[] storage d是一个引用,相当于C语言中的指针,指向data1和data2
  • 函数参数默认是memory,需要将其改成stroage类型
  • 将public改成internal类型,防止公开调用,占用大量的资源
  • 代码
pragma solidity ^0.4.0;
contract C{
    uint[] public data1;
    uint[] public data2;
    
    function append1() public {
        append(data1);
    }
    
    function append2() public {
        append(data2);
    }
    
    function append(uint[] storage d)internal{
        d.push(23);
    }
}
  • 界面

纠错(1)

代码

pragma solidity ^0.4.0;
contract C{
    uint  public a;
    uint[] public data;
    function f() public {
        uint[] storage x;
        x.push(2);
        data=x;
    }
}

界面

问题

  • a变成了一个计数器,这个是Solidity的缺陷,原因在于uint[] storage x;它是一个指针,如果没有赋值,默认指定合约地址的整个存储空间的0位置,也就是uint public a 的位置。

  • uint[] storage x,指向变量a。每次调用f函数,x 的长度就会增加,并且将存储的长度存储在变量a上,因此每次a的数值每次增加1.

  • 如果修改代码如下

pragma solidity ^0.4.0;
contract C{
    uint  public a=23;
    uint[] public data;
    function g(uint input)public{
        a = input;
    }
    function f() public {
        uint[] storage x;
        x.push(2);
        data=x;
    }
}
  • 首先取a的值,为23,点击f函数,再点击a,得到a变成24,24之前的数据不可以访问,但是24是存储的2,由代码x.push(2)来完成。g函数也是一样的效果。

修正

  • 给uint[] storage x;初始化指定默认位置,比如改成uint[] x = data;x.push(2);删除data = x;这一句

猜你喜欢

转载自blog.csdn.net/CHYabc123456hh/article/details/107014106