Note
storage、memory、calldata
Tip
EVM Architecture
參考來源
Solidity 數據儲存位置有三類:storage、memory 和 calldata,不同儲存位置的 gas
成本不同。
storage 類型數據存在鏈上,類似計算機的硬碟,消耗 gas
多。
memory 和 calldata 類型的臨時存在內存裡,消耗 gas
少。
合約裡的狀態變量默認都是 storage
,儲存在鏈上
函數裡的參數和臨時變量一般用 memory
,儲存在內存中不上鏈。
尤其是返回數據類型是變長的情況下,必須加 memory
修飾詞。
例如:string
、bytes
、array
和自訂義結構
和 memory
類似,儲存在內存中不上鏈。
與 memory
的不同點在於 calldata
變量不能修改 (immutable),一般用於函數的參數。
舉例:
function fCalldata(uint[] calldata _x) public pure returns(uint[] calldata){
// 參數為 calldata 陣列,不能被修改
// _x[0] = 0 // 這樣修改會噴錯
return(_x);
}
-
以下兩種賦值本質上是創建引用指向本體,因此修改本體或者引用,變化會被同步
storage
(合約的狀態變量) 賦值給本地storage
(函數裡) 時,會創建引用,改變新變量會影響原變量
uint[] x = [1,2,3]; // 狀態變量:陣列 x function fStorage() public{ //聲明storage的變量 xStorage,指向x。修改xStorage也會影響x uint[] storage xStorage = x; xStorage[0] = 100; }
memory
賦值給memory
,會創建引用,改變新變量會影響原變量
-
其他狀況賦值創建的是本體的副本,二者之一的修改不會影響到另一方
狀態變量的數據除存在鏈上,所有合約內部函數都可以訪問,gas
消耗高。
狀態變量在合約內,函數外部聲明
contract Variables {
uint public x = 1;
uint public y;
string public z;
}
局部變量是僅在函數執行過程中有效的變量,函數退出後變量無效。
局部變量的數據儲存在內存裡,不上鏈, gas
消耗低。
局部變量在函數內部聲明
function bar() external pure returns(uint){
uint xx = 1;
uint yy = 3;
uint zz = xx + yy;
return(zz);
}
全局變量是全局範圍工作的變量,都是 solidity 預留的關鍵字。
可以在函數內不聲明直接使用
function global() external view returns(address, uint, bytes memory){
address sender = msg.sender;
uint blockNum = block.number;
bytes memory data = msg.data;
return(sender, blockNum, data);
}
常見的全局變量有 msg.sender
、block.number
和 msg.data
等
Tip
Cancun升级新增的全局變量
block.blobbasefee
: (uint) 當前區塊的 blob 基礎費用。
blobhash(uint index)
: (bytes32) 返回跟當前交易關聯的第 index 個 blob的版本化哈希
Solidity 中不存在小數點,以 0
代替小數點,來確保交易的精確度,並且防止精度的丟失
wei
:1gwei
:1e9 = 1000000000ether
:1e18 = 1000000000000000000
seconds
:1minutes
:60 seconds = 60hours
:60 minutes = 3600days
:24 hours = 86400weeks
:7 days = 604800
-
Q: 引用類型(Reference Type)包含以下?
A: array、struct、mapping -
Q: Solidity数据存储位置的类型不包含以下?
A: stack -
Q: 合约中状态变量默认的存储位置类型为以下的?
A: storage -
Q: 不同类型的引用变量相互赋值时,修改其中一个的值,不会导致另一个的值随之改变的是以下哪种情况:?
A: 合約中的 storage 賦值給本地的 memory -
Q: Solidity中变量按作用域划分,可分为?
A: 狀態 state、局部 local、全局 global -
Q: 消耗gas最多的变量类型为?
A: 狀態變量 -
Q: 下列表示“请求发起地址”的为?
A: msg.sender -
Q: 下列表示“当前区块的矿工地址”的为?
A: block.coinbase