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;
}
}
查看编译器有如下警报:

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

从图中可以看到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
,会看到编译器的报错:

从报错中可以看到,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
,查看返回值

可以看到将状态变量中的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]);
}
}

同样,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]);
}
}
部署、调用,输出结果为:

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

因为不想重新修改上面那张图,直接补充在这里好了。
对于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]);
}
}

网友评论