2018-10-24筆記
對于變量類型做了一些試驗,得到一下一些結論:
- 根據傳遞方式來分,變量種類有按值傳遞與按引用傳遞兩種類型,引用類型有
arrays、structs、mappings。根據聲明位置分,主要有狀態(tài)變量(相當于全局變量),局部變量。 - 狀態(tài)變量的數據存儲區(qū)都是
storage,并且Mappings只可以聲明為狀態(tài)變量。 - 作為函數局部變量的引用類型變量(為了方便敘述,下用uint[]舉例,
structs是一樣的,可以自己做一下試驗),在0.5之前,如果沒有指定存儲區(qū),則默認存儲區(qū)為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,我們只執(zhí)行了一次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的存儲區(qū)顯式指定為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,查看返回值

可以看到將狀態(tài)變量中的array賦值給局部變量中的array,會將storage中的array拷貝一份到memory中。
從局部變量到狀態(tài)變量顯而易見就是拷貝了,因為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存的是狀態(tài)變量,對其做的修改應該得到保存。
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]);
}
}
部署、調用,輸出結果為:

引用類型在狀態(tài)變量跟局部變量之間的傳遞方式如下圖所示:

因為不想重新修改上面那張圖,直接補充在這里好了。
對于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]);
}
}
