Solidity - 引用類型

2018-10-24筆記


對于變量類型做了一些試驗,得到一下一些結論:

  1. 根據傳遞方式來分,變量種類有按值傳遞與按引用傳遞兩種類型,引用類型有arraysstructs、mappings。根據聲明位置分,主要有狀態(tài)變量(相當于全局變量),局部變量。
  2. 狀態(tài)變量的數據存儲區(qū)都是storage,并且Mappings只可以聲明為狀態(tài)變量。
  3. 作為函數局部變量的引用類型變量(為了方便敘述,下用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;
        }
}

查看編譯器有如下警報:


警報1.png

下面證明默認指向的位置為storage的第一個slot,將合約部署,然后調用sayhi()方法,可以得到:

a變量的值.png

從圖中可以看到a的值變成了1235,在合約中我們并沒有操作a,我們只執(zhí)行了一次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的存儲區(qū)顯式指定為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

可以看到將狀態(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]);
        }
}
輸出.png

同樣,storagestorage也是拷貝,因為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]);
        }
}

部署、調用,輸出結果為:


輸出2.png

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


引用類型的傳遞方式.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
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容