通学智能合约系列(十九)--memory与storage

Solidity-内存、引用与持久化存储

1、 内存与区块链——storage与memory原理

在前面的学习当中,我们知道了,合约中的一个被public修饰的成员变量,会默认生成一个供外部调用的函数,而这个函数是存储在区块链自身的数据结果里的。对于函数内部的局部变量,仅存在与内存当中。

我们看如下例子:

pragma solidity ^0.4.16;


contract MemoryTest{
    
    
    

 function add(uint num) view returns(uint){
    
    
     
     num += 1;
     
     return num;
     
 }
 
 
 function test() view returns(uint,uint){
    
    
     
     uint i = 2;
     
     uint j =  add(i);
     
     return(i,j);
 }
}

编译执行以上代码后,可以得到以下结果:

在这里插入图片描述

当我们改变输入的num的值,尽管add函数的返回值是变化的,但是我们test()函数的返回值,始终是23.原因是什么呢?就是因为我们的ij作为局部变量,在设置num值给add()函数的时候,仅仅是拷贝了一份副本数据给变量i,而实际参数i是确定被赋值为2的。所以j的值也是恒定为3的。这个地方大家可以类比java中的形参和实参。

具体的内存模型如下图:

在这里插入图片描述

关于我们的变量num,i,j其实都是存储在memory中的,当合约函数被执行完成之后,这些内存数据也就消失了。而对于我们的成员变量,也可能理解成我们的合约函数,是存储在storage当中的,这些数据会被永久保存。

上图,我们画的公有成员变量k,我们来尝试修改它吧。

uint public k  = 20;

 function changeIt(){
    
    
     
     add(k);
 }

编译执行之后,我们发现k值是不会发生变化的。这个相当于将区块链上的数据k重新拷贝了一份到add()函数

形参i中去做运算,实际上k的值是不会变化的。

我们下面再来看一个例子:

pragma solidity ^0.4.16;


contract MemoryTest{
    
    
    
 uint public num1 = 5;
 
 uint public num2 = num1;
 
 function test() view  returns(uint){
    
    
     
     uint i = num1;
     uint j = i;
     
     j++;
     return i;
 }
 
 function test2() view returns(uint){
    
    
     uint i = num1;
     uint j = i;
     i++;
     return i;
     
 }
}

经过编译执行后,我们发现,以上各个变量之间都是彼此独立,互不影响的。各自有自己的内存空间,修改是不会影响其他变量的。

以上我们介绍的都是我们的memory内存。

在写这篇文章的时候,我脑海中对自己提出了一个疑问,那就是智能合约到底存在哪里?

经过一番搜索,找到以下以下答案,供大家一起探讨,如果你有好的想法,可以留言发表呀~

2、 storage引用详解

在这一小节中,我们将重点介绍storage内存。

如果小伙伴们有接触过java的内存分配模型,应该都知道java的基本类型是存储在栈中的,而对象的内容或者数组的内容是存储在堆中的。如下图。

在这里插入图片描述

这里我们为什么要提到堆栈呢?主要还是因为这solidity中的memorystorage就类同于我们java啊,有没有?

下面我们来看一段代码

pragma solidity ^0.4.16;


contract StorageTest{
    
    
  // 这个状态变量存储在区块链的网络之上
  uint[] arrx;
  // 当我们传递这个可变长度数组的时候,会在内存中为它分配空间
  function test(uint[] arry) view returns(uint[]){
    
    
      // 将内存的arry拷贝给区块链上的arrx变量
      arrx = arry;
      // 当我们在函数体内部定义了一个可变长度的数组时,实际上,他默认的类型是storage类型。
      uint[] z = arrx;
      
      return z;
  }
      
 }

针对storage类型的操作

pragma solidity ^0.4.16;


contract StorageTest{
    
    
    
  uint[] arrx;
  
  function test(uint[] arry) view returns(uint){
    
    
      arrx = arry;
      // 当我们在函数体内部定义了一个可变长度的数组时,实际上,他默认的类型是storage类型,
      他指向了区块链上的arrx,所以当我修改z的元素的时候,我们实际上再操作的是区块链上的arrx
      uint[] z = arrx;
      // 通过指针实际身上修改了区块链上的arrx的值
      z[0] = 100;
      //通过指针实际上修改了区块链上arrx的长度,说明z和zrrx其实是一样的,操作z的时候,会改变arrx的值。
      z.length = 100;
      
      return z[0];
  }
  // 返回arrx的第一个元素
  function test2() returns(uint){
    
    
      return arrx[0];
  }
  // 返回arrx的长度
  function test3() returns(uint){
    
    
      return arrx.length;
  }
      
 }

关于solidity的两种内存特性就介绍到这里。

通学技术 面向区块链编程 学通技术 构建可信任社会

猜你喜欢

转载自blog.csdn.net/aiwaston/article/details/118314056