详述Solidity数据类型之二:引用类型

曹瑞丽
曹瑞丽 2018-05-17 10:37
1 7116
作者:梁雁明
著权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
<p>引用类型
复杂类型, 例如不能匹配256bit类型,而且必须要被比我们已经知道的值类型更加小心处理的类型.因为复制值类型是代价是高昂的,所以我们必须试想如何在内部中(非实例化)或存储它们。
<p>数据位置
每一个复杂的类型,像 arrays 和structs, 都有额外的标注, 即"data location", 关于它们是保存在内部中还是存储中. 根据上下文环境, 总有默认值,当然可以通过追加关键字storage 或 memory去进行覆盖.函数参数(包括返回类型)的默认类型是 memory, 而本地变量的默认类型是 storage ,而且状态变量的位置标注会被强制转化为 storage (明显的).
还有第三种位置类型标注calldata, 当函数变量被保存时,是不可改变及不可持久化的. 外部函数参数(非返回参数) 强制为 calldata 而行为方式与 memory相类似。
数据位置标注是很重要的,因为他可以改变分配的行为方式: storage和memory之间的分配,而且,一个状态变量(即使从别的状态变量而来的) 总是生成一份独立的数据复制区域. 对于本地存储变量的分配只是分配引用, 这一引用总是指向即使后者会被同时被改变的状态变量上,别一方面,内存存储引用类型的分配到另一内存存储引用并不会产生数据复制。
<p>总结
<b>固定<b>的数据位置<b>:
<p>·       外部函数的参数(非返回参数): calldata
<p>·       状态变量: storage
<b>默<b>认<b>的数据位置<b>:
<p>·       函数参数(包括返回参数): memory
<p>·       所有本地变量: storage
<p>·      <b>数<b>组
<p>·      数组在编译期间有固定的大小或者数组可以动态变化.对于存储数组, 其元素类型是任意的(例如别的arrays, mappings 或structs). 对于内存数组, 其元素不能是mapping ,而且如果其成员是公共可见函数,还必须是ABI 类型的一种。
固定大小 k 且元素类型为 T 的数组书写形式为 T[k],动态大小数组的书写形式为 T[]. 举例说明,一个包括5个动态 uint 数组的数组表式为uint[][5] (与其它语言相对比,标记顺序是相反的).你可以使用x[2][1] 用获得第三个数组中的第二个元素(下标基于0,获取方式与声明相反的形式i.e. x[2] shaves off one level in the type from the right).
<p>·      bytes 和 string 是比较特殊的数组.  bytes 等价于 byte[],在calldata中被打包了. string 等价于 bytes 不允许长度或下标的索引获取(目前).
<p>·      所以 bytes 是优于 byte[] 使用的,因为它更省开销.
·       <b>注解
·       如果你想获得字符串s的字节表示形式, 那么你可以使用如下方式: bytes(s).length / bytes(s)[7] = 'x';. 请牢记你将获得到的是低等级的UTF-8字节表示,并不包括其它特殊的字符!
<p>·      可以为数据标记为public 而且Solidity会为其创建一个 getter方法. 在调用getter方法时,数字下标是被要求的.
<p>·      <b>分配内存数<b>组
<p>·      可以通过使用new 关键字在内存中创建可变长度的数组与storage 数组相对, 不可以向通过指 .length 成员来重新定义memory数组的大小.
·      pragma solidity ^0.4.16;
·      contract C {
·          function f(uint len) public pure {
·              uint[] memory a = new uint[](7);
·              bytes memory b = new bytes(len);
·              // Here we have a.length == 7 and b.length == len
·              a[6] = 8;
·          }
·       }
<p>·      <b>数<b>组<b>常量<b>/<b>内<b>联<b>数<b>组
<p>·      数组常量是当前未被分配到任何变量,并以表达式形式表示的数组.
·      pragma solidity ^0.4.16;
·      contract C {
·          function f() public pure {
·              g([uint(1), 2, 3]);
·          }
·          function g(uint[3] _data) public pure {
·              // ...
·          }
·       }
<p>·      常量数组类型是一个通常元素类型且固定大小的内存数组.  [1, 2, 3] 的类型为 uint8[3] memory, 因为数组的每一个常量类型是 uint8.基于此,必然可以将第一个元素存放在上面的 uint. 请注意, 当前,固定大小的内存数组不能被指向于一个动态大小的内存数组,示例如下,这种方式是不被允许的:
·      // This will not compile.
·      pragma solidity ^0.4.0;
·      contract C {
·          function f() public {
·              // The next line creates a type error because uint[3] memory
·              // cannot be converted to uint[] memory.
·              uint[] x = [uint(1), 3, 4];
·          }
·       }
<p>·      本来打算是要将这限制人未来一段时间去掉的,但是目前,在处理数组如何在ABI传递时出现了一些难题.
<p>·      <b>成<b>员
<p>·       <b>length:
·      数组成员 length 表示成员的个数. 动态数组可以在storage(not in memory)改变 .length 成员重新指定大小. 当尝试以超过数组大小的方式获得数组元素时,这种方式不会自动执行,内存数组的大小在创建时就被固定了(但如果是动态数组,依赖于其运行时的参数)
<p>·       <b>push:
·      动态storage 数组和bytes (而不是string) 拥有名叫push 的成员方法,用于在数组尾部追回元素. 该函数返回数组的最新长度.
·       <b>警告
·       目前尚不能在外部函数中使用数组的数组(多维数组).
·       <b>警告
·       基于EVM的限制, 可能够从外部的函数调用返回动态内容. 函数f 在contract C { function f() returns (uint[]) { ... } } 在web3.js调用的话,会返回一些值, 但在Solidity中使用时不会返回任何东西.
·       The only workaround for now is to use large statically-sized arrays.
·      pragma solidity ^0.4.16;
·      contract ArrayContract {
·          uint[2**20] m_aLotOfIntegers;
·          // Note that the following is not a pair of dynamic arrays but a
·          // dynamic array of pairs (i.e. of fixed size arrays of length two).
·          bool[2][] m_pairsOfFlags;
·          // newPairs is stored in memory - the default for function arguments
·      
<p>
·          function setAllFlagPairs(bool[2][] newPairs) public {
·              // assignment to a storage array replaces the complete array
·              m_pairsOfFlags = newPairs;
·          }
·          function setFlagPair(uint index, bool flagA, bool flagB) public {
·              // access to a non-existing index will throw an exception
·              m_pairsOfFlags[index][0] = flagA;
·              m_pairsOfFlags[index][1] = flagB;
·          }
·          function changeFlagArraySize(uint newSize) public {
·              // if the new size is smaller, removed array elements will be cleared
·              m_pairsOfFlags.length = newSize;
·          }
·          function clear() public {
·              // these clear the arrays completely
·              delete m_pairsOfFlags;
·              delete m_aLotOfIntegers;
文章发布只为分享区块链技术内容,版权归原作者所有,观点仅代表作者本人,绝不代表区块链兄弟赞同其观点或证实其描述。
1条回应 最新 最早
周妍
沙发# 周妍 2018-05-17 10:38
基于区块链技术的数字货币,本身当然具有一定的价值,但这种价值建立在其指代的现实标的物上。数字货币与其所指代的现实标的物价值合一,才能与现实经济生活融为一体。
游客
登录后才可以回帖,登录 或者 注册