原文:《Solidity 極簡入門: 4. 變量數據存儲和作用域storage/memory/calldata》

作者:0xAA

我最近在重新學solidity,鞏固一下細節,也寫一個「Solidity 極簡入門」,供小白們使用(編程大佬可以另找教程),每週更新1-3 講。

所有代碼開源在:github.com/AmazingAng/WTFSolidity

Solidity 中的引用類型

引用類型(Reference Type):包括數組(array),結構體(struct)和映射(mapping),這類變量佔空間大,賦值時候直接傳遞地址(類似指針)。由於這類變量比較複雜,佔用存儲空間大,我們在使用時必須要聲明數據存儲的位置。

數據位置

solidity 數據存儲位置有三類:storage,memory 和calldata。不同存儲位置的gas 成本不同。 storage 類型的數據存在鏈上,類似計算機的硬盤,消耗gas 多;memory 和calldata 類型的臨時存在內存裡,消耗gas 少。大致用法:

1.storage:合約裡的狀態變量默認都是storage,存儲在鏈上。

2.memory:函數里的參數和臨時變量一般用memory,存儲在內存中,不上鍊。

3.calldata:和memory 類似,存儲在內存中,不上鍊。與memory 的不同點在於calldata 變量不能修改(immutable),一般用於函數的參數。例子:

Solidity極簡入門 | 第四講:變量數據存儲和作用域

不同類型相互賦值時的規則

在不同存儲類型相互賦值時候,有時會產生獨立的副本(修改新變量不會影響原變量),有時會產生引用(修改新變量會影響原變量)。規則如下:

1.storage(合約的狀態變量)賦值給本地storage(函數里的)時候,會創建引用,改變新變量會影響原變量。例子:

Solidity極簡入門 | 第四講:變量數據存儲和作用域

1.storage 賦值給memory,會創建獨立的複本,修改其中一個不會影響另一個;反之亦然。例子:

Solidity極簡入門 | 第四講:變量數據存儲和作用域

1.memory 賦值給memory,會創建引用,改變新變量會影響原變量。

2.其他情況,變量賦值給storage,會創建獨立的複本,修改其中一個不會影響另一個。

變量的作用域

Solidity 中變量按作用域劃分有三種,分別是狀態變量(state variable),局部變量(local variable)和全局變量(global variable)

1. 狀態變量

狀態變量是數據存儲在鏈上的變量,所有合約內函數都可以訪問,gas 消耗高。狀態變量在合約內、函數外聲明:

Solidity極簡入門 | 第四講:變量數據存儲和作用域

我們可以在函數里更改狀態變量的值:

Solidity極簡入門 | 第四講:變量數據存儲和作用域

2. 局部變量

局部變量是僅在函數執行過程中有效的變量,函數退出後,變量無效。局部變量的數據存儲在內存裡,不上鍊,gas 低。局部變量在函數內聲明:

Solidity極簡入門 | 第四講:變量數據存儲和作用域

3. 全局變量

全局變量是全局範圍工作的變量,都是solidity 預留關鍵字。他們可以在函數內不聲明直接使用:

Solidity極簡入門 | 第四講:變量數據存儲和作用域

在上面例子裡,我們使用了3 個常用的全局變量:msg.sender, block.number 和msg.data,他們分別代表請求發起地址,當前區塊高度,和請求數據。下面是一些常用的全局變量,更完整的列表請看這個鏈接:

· blockhash(uint blockNumber): (bytes32) 給定區塊的哈希值– 只適用於256 最近區塊, 不包含當前區塊。

· block.coinbase: (address payable) 當前區塊礦工的地址

· block.gaslimit: (uint) 當前區塊的gaslimit

· block.number: (uint) 當前區塊的number

· block.timestamp: (uint) 當前區塊的時間戳,為unix 紀元以來的秒

· gasleft(): (uint256) 剩餘gas

· msg.data: (bytes calldata) 完整call data

· msg.sender: (address payable) 消息發送者(當前caller)

· msg.sig: (bytes4) calldata 的前四個字節(function identifier)

· msg.value: (uint) 當前交易發送的wei 值

· now : (uint) 當前塊的時間戳

總結

在第4 講,我們介紹了solidity 中的引用類型,數據位置和變量的作用域。重點是storage, memory 和calldata 三個關鍵字的用法。他們出現的原因是為了節省鏈上有限的存儲空間和降低gas。下一講我們會介紹引用類型中的數組。