solidity智能合约存储特性

以太坊评论892阅读模式
摘要

solidity智能合约的一些重要特性,如变长数组中的storage和memory变量,storage和memory的存储位置以及字符串数组string[]使用。

一. 关于变长数组。

string[],bytes[]

对于变长数组,在初始化分配空间前不可使用,可以通过new关键字来初始化一个数组。它们不能在使用new关键字初始化前使用下标方式访问。

storage

storage类型的动态数组有一个length属性,表示当前的数组长度。对于storage的变长数组,可以通过给length赋值调整数组长度。可以通过两种方式改变数组长度,index++及push方法。

contract test{
    
    string[] strs = new string[](0);
    
    function test1() public returns(uint, string[]){
        strs[strs.length++] = "a1";
        return (strs.length, strs);
    }
    
    function test2() public returns(uint, string[]){
        strs.push("b1");
        return (strs.length, strs);
    }
}

memory

而memory类型的动态数组,不支持修改length属性来调整数组大小。一旦new完,大小不可改变。

二. 存储位置storage和memory

memory赋值给storage

contract test1{
    int i;
    struct S{string a;uint b;}

    function assign(S s) internal{
        S tmp = s;  // 报错,tmp是局部变量(storage类型),s是函数参数(memory类型)
    }
    function change(int changei) public returns(int){
        i = changei;
        return i; // 返回等于changei的值
    }
}

storage转换为storage

contract test2{
    
    struct S{string a;uint b;}
    
    //状态变量,合约内声明的公有变量,默认是storage的
    S s;
    
    function convertStorage(S storage s) internal{
        S tmp = s;  // tmp也是storage类型的
        tmp.a = "Test";
    }
    
    function call() returns (string){
        convertStorage(s);
        return s.a;//Test
    }
}

memory赋值给storage

contract test3{
  struct S{string a;uint b;}

  //默认是storage的
  S s;

  function memoryToState(S memory tmp) internal{
    s = tmp; //tmp是memory的,从内存中复制到状态变量中。

    //修改旧memory中的值,并不会影响状态变量
    tmp.a = "Test";
  }

  function call() returns(string){
    S memory tmp = S("memory", 0);
    memoryToState(tmp);

    return s.a;
  }
}

memory赋值给局部变量(storage)

contract test4{
  struct S{string a;uint b;}

  function memoryToLocal(S s) internal{
    S tmp = s;  // 报错,tmp是局部变量(storage类型),s是函数参数(memory类型)
    
    //修改变量为memory类型, 不会报错
    S memory tmp = s;
  }
}

storage赋值memory

contract test5{
    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; //storage
    }
}

memory赋值memory

memory之间是引用传递,并不会拷贝数据。一个memory的引用类型赋值给另一个memory的引用,不会创建另一个新的拷贝。

contract test6{
  struct S{string a;uint b;}

  //默认参数是memory
  function memoryToMemory(S s) internal{
    S memory tmp = s; // tmp是memory,s是memory

    //引用传递
    tmp.a = "other memory";
  }

  function call() returns (string){
    S memory mem = S("memory", 1);
    memoryToMemory(mem);
    return mem.a;//other memory
  }
}

三. 字符串数组string[]

    function getEntry(string[] fields, Entry entry) internal view returns (string[]) {
        //string[] values = new string[](fields.length); 报错,values是storage类型的,后面是memory
        for (uint i = 0; i < fields.length; i++) {
            values[i] = entry.getString(fields[i]);
        }
        return values;
    }

 

    function getEntry(string[] fields, Entry entry) internal view returns (string[]) {
        string[] memory values = new string[](fields.length); // 正确
        for (uint i = 0; i < fields.length; i++) {
            values[i] = entry.getString(fields[i]);
        }
        return values;
    }

以太坊之数据存储详解 以太坊

以太坊之数据存储详解

本文整理分析以太坊网络中的区块、交易以及合约数据是如何存储的。 区块结构 区块由两部分组成,分别是区块头(header)和区块体(body)两部分,详细结构图如下。 区块头(header) 区块头存储...
FISCO BCOS证书与鉴权体系 BCOS

FISCO BCOS证书与鉴权体系

区块链之所以被称为“信任的机器”,是因为其通过密码学算法使各不信任的节点互相协作达到信任。这一理念在联盟链中的体现主要是基于PKI(公钥基础设施)建立证书体系,FISCO BCOS中的证书主要满足SS...
Solidity合约间调用原子性操作实验 BCOS

Solidity合约间调用原子性操作实验

实验说明 为了测试在合约内调用另一个合约时,若在某一方法内,先调用另一个合约方法导致其数据更改成功,而执行后面的语句时由于某些原因导致交易失败,那么已经被调用的合约数据已然更改还是未被更改?针对这个问...