美文网首页
Solidity - 引用类型

Solidity - 引用类型

作者: Llewyn_Davis | 来源:发表于2018-10-24 17:57 被阅读0次

2018-10-24笔记


对于变量类型做了一些试验,得到一下一些结论:

  1. 根据传递方式来分,变量种类有按值传递与按引用传递两种类型,引用类型有arraysstructsmappings。根据声明位置分,主要有状态变量(相当于全局变量),局部变量。
  2. 状态变量的数据存储区都是storage,并且Mappings只可以声明为状态变量。
  3. 作为函数局部变量的引用类型变量(为了方便叙述,下用uint[]举例,structs是一样的,可以自己做一下试验),在0.5之前,如果没有指定存储区,则默认存储区为storage,且是作为“指针”的形式存在,如果声明的时候没有进行初始化,编译器会出现警告,此时默认指向storage的第一个slot
实验举例

开始做试验,假设有如下合约,

pragma solidity ^0.4.0;
contract hello {
        uint a = 1234;
        uint[] d_arr;
        function sayhi() public returns(uint) {
                uint[] p;
                p.push(1000);
                return a;
        }
}

查看编译器有如下警报:


警报1.png

下面证明默认指向的位置为storage的第一个slot,将合约部署,然后调用sayhi()方法,可以得到:

a变量的值.png

从图中可以看到a的值变成了1235,在合约中我们并没有操作a,我们只执行了一次push操作(这个操作会将.length的值加1),因此可以断定,p指向了a,并且astorage的第一个slot中(关于这点放在变量布局中讲)。


将合约稍微改一下:

pragma solidity ^0.4.0;
contract hello {
        uint a = 1234;
        uint[] d_arr;
        function sayhi() public returns(uint) {
                uint[] memory p=d_arr;
                p.push(1000);
                return a;
        }
}

我们将p的存储区显式指定为memory,会看到编译器的报错:

错误.png

从报错中可以看到,memory中不可以使用push操作(pop也不可以),另外使用new声明的数组,虽然可以在运行时候指定数组的长度,但是声明后依旧不可以修改数组的length值,下面是对官方文档的引用:

You can use the new keyword to create arrays with a runtime-dependent length in memory. As opposed to storage arrays, it is not possible to resize memory arrays.


下面再看一下,从storagememory的引用类型变量的传递情况。

pragma solidity ^0.4.0;
contract hello {
        uint a = 1234;
        uint[] d_arr = [123, 456];
        function sayhi() public view returns(uint, uint) {
                uint[] memory p=d_arr;
                p[0] = 321;
                return (p[0], d_arr[0]);
        }
}

部署、调用sayhi,查看返回值

返回值.png

可以看到将状态变量中的array赋值给局部变量中的array,会将storage中的array拷贝一份到memory中。


从局部变量到状态变量显而易见就是拷贝了,因为memory在每次方法运行前,都会"清洗"干净。

pragma solidity ^0.4.0;
contract hello {
        uint a = 1234;
        uint[] d_arr;
        function sayhi() public  returns(uint, uint) {
                uint[3] memory p = [uint(1),2,3];
                d_arr = p;
                p[0] = 123;
                return (p[0], d_arr[0]);
        }
}
输出.png

同样,storagestorage也是拷贝,因为storage存的是状态变量,对其做的修改应该得到保存。

pragma solidity ^0.4.0;
contract hello {
        uint a = 1234;
        uint[] d_arr = [1, 2, 3];
        uint[] d_arr1 = [4, 5, 6];
        function sayhi() public  returns(uint, uint) {
                d_arr1 = d_arr;
                d_arr[0] = 100;
                return (d_arr[0], d_arr1[0]);
        }
}

部署、调用,输出结果为:


输出2.png

引用类型在状态变量跟局部变量之间的传递方式如下图所示:


引用类型的传递方式.png

因为不想重新修改上面那张图,直接补充在这里好了。
对于memorymemory之间的传递方式时传递引用。

pragma solidity ^0.4.0;
contract hello {
        function sayhi() public pure returns(uint, uint) {
            uint[3] memory p1 = [uint(1), 2, 3];
            uint[3] memory p2 = [uint(4), 5, 5];
            p1 = p2;
            p2[0] = 10;
            return (p1[0], p2[0]);
        }
}
memory之间的传递.png

相关文章

网友评论

      本文标题:Solidity - 引用类型

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