美文网首页
Solidity开发指南(八):memory和storage

Solidity开发指南(八):memory和storage

作者: 米饭超人 | 来源:发表于2018-06-01 22:05 被阅读50次

    在区块链里,区块链本身就是一个数据库。如果你使用区块链标记物产的所有权,归属信息将会被记录到区块链上,所有人都无法篡改,以标明不可争议的拥有权。所以在区块链中编程中,有一个数据位置的属性用来标识变量是否需要持久化到区块链中。

    变量的存储有三种类型,memory,storage和calldata。最后一种数据位置比较特殊,一般只有外部函数的参数(不包括返回参数)被强制指定为calldata。这种数据位置是只读的,不会持久化到区块链。一般我们可以选择指定的是memory和storage。

    memory存储位置同我们普通程序的内存类似。即分配,即使用,越过作用域即不可被访问,等待被回收。而对于storage的变量,数据将永远存在于区块链上。

    1.默认的函数参数,包括返回的参数,他们是memory。而默认的局部变量是storage的。

    pragma solidity ^0.4.0;
    contract SimpleAssign{
      struct S{string a;uint b;}
    
      //默认参数是memory
      function assign(S s) internal{
        //默认的变量是storage的指针
        //Type struct MemoryToLocalVar.S memory is not implicitly convertible to expected type struct MemoryToLocalVar.S storage pointer.
        //S tmp = s;
      }
    }
    
    pragma solidity ^0.4.0;
    contract StateVariable{
      struct S{string a;uint b;}
      //状态变量,默认是storage
      S s;
    }
    

    2.storage转换为storage

    pragma solidity ^0.4.0;
    contract StorageConvertToStorage{
      struct S{string a;uint b;}
    
      //默认是storage的
      S s;
    
      function convertStorage(S storage s) internal{
        S tmp = s;
        tmp.a = "Test";
      }
    
      function call() returns (string){
        convertStorage(s);
        return s.a;//Test
      }
    }
    

    在上面的代码中,我们将传入的storage变量,赋值给另一个临时的storage类型的tmp时,并修改tmp.a = "Test",最后我们发现合约的状态变量s也被修改了。

    3.memory赋值给状态变量
    将一个memory类型的变量赋值给一个状态变量时,实际是将内存变量拷贝到存储中。

    pragma solidity ^0.4.0;
    
    contract MemoryConvertToStateVariable{
      struct S{string a;uint b;}
    
      //默认是storage的
      S s;
    
      function memoryToState(S memory tmp) internal{
        s = tmp;//从内存中复制到状态变量中。
    
        //修改旧memory中的值,并不会影响状态变量
        tmp.a = "Test";
      }
    
      function call() returns(string){
        S memory tmp = S("memory", 0);
        memoryToState(tmp);
    
        return s.a;
      }
    }
    

    通过上例,我们发现,在memoryToState()中,我们把tmp赋值给s后,再修改tmp值,并不能产生任何变化。赋值时,完成了值拷贝,后续他们不再有任何的关系。

    4.memory赋值给局部变量
    由于在区块链中,storage必须是静态分配存储空间。局部变量虽然是一个storage的,但它仅仅是一个storage类型的指针。如果进行这样的赋值,实际会产生一个错误。

    pragma solidity ^0.4.0;
    contract MemoryToLocalVar{
      struct S{string a;uint b;}
    
      //默认参数是memory
      function memoryToLocal(S s) internal{
        //默认的变量是storage的指针
        //Type struct MemoryToLocalVar.S memory is not implicitly convertible to expected type struct MemoryToLocalVar.S storage pointer.
        //S tmp = s;
        
        //修改变量为memory类型
        S memory tmp = s;
      }
    }
    

    通过上面的代码,我们可以看到这样的赋值的确不被允许。你可以通过将变量tmp改为memory来完成这样的赋值。

    5.storage转为memory
    将storage转为memory,实际是将数据从storage拷贝到memory中。

    pragma solidity ^0.4.0;
    contract StorageToMemory{
      struct S{string a;uint b;}
    
      S s = S("storage", 1);
    
      function storageToMemory(S storage x) internal{
        S memory tmp = x;//由Storage拷贝到memory中
    
        //memory的修改不影响storage
        tmp.a = "Test";
      }
    
      function call() returns (string){
        storageToMemory(s);
        return s.a;
      }
    }
    

    在上面的例子中,我们看到,拷贝后对tmp变量的修改,完全不会影响到原来的storage变量。

    6.memory转为memory
    memory之间是引用传递,并不会拷贝数据。

    pragma solidity ^0.4.0;
    contract MemoryToMemory{
      struct S{string a;uint b;}
    
      //默认参数是memory
      function memoryToMemory(S s) internal{
        S memory tmp = s;
    
        //引用传递
        tmp.a = "other memory";
      }
    
      function call() returns (string){
        S memory mem = S("memory", 1);
        memoryToMemory(mem);
        return mem.a;//other memory
      }
    }
    

    在上面的代码中,memoryToMemory()传递进来了一个memory类型的变量,在函数内将之赋值给tmp,修改tmp的值,发现外部的memory也被改为了other memory。

    相关文章

      网友评论

          本文标题:Solidity开发指南(八):memory和storage

          本文链接:https://www.haomeiwen.com/subject/kjflsftx.html