2018-10-24笔记
对于变量类型做了一些试验,得到一下一些结论:
- 根据传递方式来分,变量种类有按值传递与按引用传递两种类型,引用类型有
arrays、structs、mappings。根据声明位置分,主要有状态变量(相当于全局变量),局部变量。 - 状态变量的数据存储区都是
storage,并且Mappings只可以声明为状态变量。 - 作为函数局部变量的引用类型变量(为了方便叙述,下用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,并且a在storage的第一个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.
下面再看一下,从storage到memory的引用类型变量的传递情况。
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
同样,storage到storage也是拷贝,因为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
因为不想重新修改上面那张图,直接补充在这里好了。
对于memory跟memory之间的传递方式时传递引用。
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









网友评论