Solidity:變量數據存儲和作用域 storage/memory/calldata

Solidity中的引用類型?

引用類型(Reference Type):包括數組(array)和結構體(struct),由于這類變量比較復雜,占用存儲空間大,我們在使用時必須要聲明數據存儲的位置。

數據位置?

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

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

  2. memory函數里的參數和臨時變量一般用memory,存儲在內存中,不上鏈。尤其是如果返回數據類型是變長的情況下,必須加memory修飾,例如:string, bytes, array和自定義結構。

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

    function fCalldata(uint[] calldata _x) public pure returns(uint[] calldata){//參數為calldata數組,不能被修改// _x[0] = 0 //這樣修改會報錯return(_x);
    }

    數據位置和賦值規則?

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

  4. 賦值本質上是創建引用指向本體,因此修改本體或者是引用,變化可以被同步:

  • storage(合約的狀態變量)賦值給本地storage(函數里的)時候,會創建引用,改變新變量會影響原變量。例子:
uint[] x = [1,2,3]; // 狀態變量:數組 xfunction fStorage() public{//聲明一個storage的變量 xStorage,指向x。修改xStorage也會影響xuint[] storage xStorage = x;xStorage[0] = 100;
}
  • memory賦值給memory,會創建引用,改變新變量會影響原變量。
  • 其他情況下,賦值創建的是本體的副本,即對二者之一的修改,并不會同步到另一方

變量的作用域?

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

1. 狀態變量?

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

contract Variables {uint public x = 1;uint public y;string public z;
}

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

function foo() external{// 可以在函數里更改狀態變量的值x = 5;y = 2;z = "0xAA";
}

2. 局部變量?

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

function bar() external pure returns(uint){uint xx = 1;uint yy = 3;uint zz = xx + yy;return(zz);
}

3. 全局變量?

全局變量是全局范圍工作的變量,都是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);
}

在上面例子里,我們使用了3個常用的全局變量:msg.senderblock.numbermsg.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?值
  • block.blobbasefee: (uint) 當前區塊的blob基礎費用。這是Cancun升級新增的全局變量。
  • blobhash(uint index): (bytes32) 返回跟當前交易關聯的第?index?個blob的版本化哈希(第一個字節為版本號,當前為0x01,后面接KZG承諾的SHA256哈希的最后31個字節)。若當前交易不包含blob,則返回空字節。這是Cancun升級新增的全局變量。

4. 全局變量-以太單位與時間單位?

以太單位?

Solidity中不存在小數點,以0代替為小數點,來確保交易的精確度,并且防止精度的損失,利用以太單位可以避免誤算的問題,方便程序員在合約中處理貨幣交易。

  • wei: 1
  • gwei: 1e9 = 1000000000
  • ether: 1e18 = 1000000000000000000
function weiUnit() external pure returns(uint) {assert(1 wei == 1e0);assert(1 wei == 1);return 1 wei;
}function gweiUnit() external pure returns(uint) {assert(1 gwei == 1e9);assert(1 gwei == 1000000000);return 1 gwei;
}function etherUnit() external pure returns(uint) {assert(1 ether == 1e18);assert(1 ether == 1000000000000000000);return 1 ether;
}

時間單位?

可以在合約中規定一個操作必須在一周內完成,或者某個事件在一個月后發生。這樣就能讓合約的執行可以更加精確,不會因為技術上的誤差而影響合約的結果。因此,時間單位在Solidity中是一個重要的概念,有助于提高合約的可讀性和可維護性。

  • seconds: 1
  • minutes: 60 seconds = 60
  • hours: 60 minutes = 3600
  • days: 24 hours = 86400
  • weeks: 7 days = 604800
function secondsUnit() external pure returns(uint) {assert(1 seconds == 1);return 1 seconds;
}function minutesUnit() external pure returns(uint) {assert(1 minutes == 60);assert(1 minutes == 60 seconds);return 1 minutes;
}function hoursUnit() external pure returns(uint) {assert(1 hours == 3600);assert(1 hours == 60 minutes);return 1 hours;
}function daysUnit() external pure returns(uint) {assert(1 days == 86400);assert(1 days == 24 hours);return 1 days;
}function weeksUnit() external pure returns(uint) {assert(1 weeks == 604800);assert(1 weeks == 7 days);return 1 weeks;
}

測試代碼:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;contract DataStorage {// The data location of x is storage.// This is the only place where the// data location can be omitted.uint[] public x = [1,2,3];function fStorage() public{//聲明一個storage的變量xStorage,指向x。修改xStorage也會影響xuint[] storage xStorage = x;xStorage[0] = 100;}function fMemory() public view{//聲明一個Memory的變量xMemory,復制x。修改xMemory不會影響xuint[] memory xMemory = x;xMemory[0] = 100;xMemory[1] = 200;uint[] memory xMemory2 = x;xMemory2[0] = 300;}function fCalldata(uint[] calldata _x) public pure returns(uint[] calldata){//參數為calldata數組,不能被修改// _x[0] = 0 //這樣修改會報錯return(_x);}
}contract Variables {uint public x = 1;uint public y;string public z;function foo() external{// 可以在函數里更改狀態變量的值x = 5;y = 2;z = "0xAA";}function bar() external pure returns(uint){uint xx = 1;uint yy = 3;uint zz = xx + yy;return(zz);}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);}function weiUnit() external pure returns(uint) {assert(1 wei == 1e0);assert(1 wei == 1);return 1 wei;}function gweiUnit() external pure returns(uint) {assert(1 gwei == 1e9);assert(1 gwei == 1000000000);return 1 gwei;}function etherUnit() external pure returns(uint) {assert(1 ether == 1e18);assert(1 ether == 1000000000000000000);return 1 ether;}function secondsUnit() external pure returns(uint) {assert(1 seconds == 1);return 1 seconds;}function minutesUnit() external pure returns(uint) {assert(1 minutes == 60);assert(1 minutes == 60 seconds);return 1 minutes;}function hoursUnit() external pure returns(uint) {assert(1 hours == 3600);assert(1 hours == 60 minutes);return 1 hours;}function daysUnit() external pure returns(uint) {assert(1 days == 86400);assert(1 days == 24 hours);return 1 days;}function weeksUnit() external pure returns(uint) {assert(1 weeks == 604800);assert(1 weeks == 7 days);return 1 weeks;}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/42807.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/42807.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/42807.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HarmonyOS ArkUi 字符串<展開/收起>功能

效果圖: 官方API: ohos.measure (文本計算) 方式一 measure.measureTextSize 跟方式二使用一樣,只是API調用不同,可仔細查看官網方式二 API 12 Preview Component export struct CustomTextSpan {State maxLines: number 1/…

迭代器模式(大話設計模式)C/C++版本

迭代器模式 C #include <iostream> #include <string> #include <vector>using namespace std;// 迭代抽象類,用于定義得到開始對象、得到下一個對象、判斷是否到結尾、當前對象等抽象方法&#xff0c;統一接口 class Iterator { public:Iterator(){};virtu…

作為產品經理,如何用大模型給我們賦能?非常詳細,收藏我這篇就夠了

作為一名產品經理&#xff0c;如果您考慮轉行至大模型領域&#xff0c;您將能夠將產品管理技能與大模型技術相結合&#xff0c;從而在產品開發和創新方面獲得一系列好處。以下是轉行大模型對產品經理的一些潛在益處&#xff1a; 更深入的技術理解&#xff1a;了解大模型技術將…

LeetCode 1351, 1, 208

目錄 1351. 統計有序矩陣中的負數題目鏈接標簽簡答二分查找思路代碼 優化思路代碼 1. 兩數之和題目鏈接標簽思路代碼 208. 實現 Trie (前綴樹)題目鏈接標簽思路代碼 1351. 統計有序矩陣中的負數 題目鏈接 1351. 統計有序矩陣中的負數 標簽 數組 二分查找 矩陣 簡答二分查找…

使用 Python 處理 Lumerical 導出的 .txt 文件(完結)

使用 Python 處理 Lumerical 導出的 .txt 文件 引言正文以 , 隔開的波長與透射率以 \t 隔開的波長與透射率引言 之前在 添加鏈接描述 一文中我們已經介紹了如何將 Lumerical 仿真中的 S 參數相關數據導出為 .txt 文件。這里我們來分享如何使用 Python 對這些數據進行處理。 正…

如果國產BI工具也有頂流,它們一定會上榜

在數據驅動的今天&#xff0c;商業智能&#xff08;BI&#xff09;工具已成為企業不可或缺的助手&#xff0c;它們通過強大的數據處理和分析能力&#xff0c;幫助企業洞察市場趨勢&#xff0c;優化運營決策。如果BI工具界也有“頂流”&#xff0c;那么奧威BI、帆軟BI&#xff0…

原生CSS變量

原生CSS 變量 css中我們可以統一設置 變量 方便頁面維護 聲明 變量聲明的時候&#xff0c;變量名之前加上兩根連詞線&#xff08;–&#xff09;即可。例如&#xff1a; 聲明的變量是有作用域的&#xff0c;比如是在html中聲明的變量&#xff0c;那么該變量在html中的任何地方都…

我國甜菜堿行業規模較大 未來行業發展前景較好

我國甜菜堿行業規模較大 未來行業發展前景較好 甜菜堿化學名稱三甲基甘氨酸&#xff0c;是一種在動植物體內廣泛存在的季銨型生物堿。它具有多種生物學功能&#xff0c;包括滲透調節、甲基供體等&#xff0c;廣泛應用于飼料、食品、醫藥和化妝品等行業。甜菜堿的提取主要來源于…

揭秘SmartEDA:電路仿真軟件如何貫穿課前課中課后,助力電子學習新紀元!

在電子設計與自動化的學習道路上&#xff0c;一款強大的電路仿真軟件往往能為學生們帶來事半功倍的效果。今天&#xff0c;我們就來深入探討一下SmartEDA這款電路仿真軟件在課前、課中、課后的全方位應用&#xff0c;看看它如何助力我們的電子學習步入新紀元&#xff01; 1、課…

直播平臺集成美顏工具詳解:視頻美顏SDK開發指南

本篇文章&#xff0c;小編將詳細介紹如何在直播平臺中集成美顏工具&#xff0c;幫助開發者更好地理解視頻美顏SDK的開發過程。 一、美顏工具的作用和原理 1.1 美顏工具的作用 美顏工具主要用于提升直播視頻的畫面質量&#xff0c;讓主播和觀眾在鏡頭前看起來更加美觀。這些功…

2024年最新ComfyUI漢化及manager插件安裝詳解!

前言 在ComfyUI文生圖詳解中&#xff0c;學習過如果想要安裝相應的模型&#xff0c;需要到模型資源網站&#xff08;抱抱臉、C站、魔塔、哩布等&#xff09;下載想要的模型&#xff0c;手動安裝到ComfyUI安裝目錄下對應的目錄中。 為了簡化這個流程&#xff0c;我們需要安裝Co…

MacOS下更新curl

蘋果自帶的curl不支持Https&#xff0c;我們可以通過curl -V看到如下結果 curl 7.72.0 (x86_64-apple-darwin18.6.0) libcurl/7.72.0 zlib/1.2.12 libidn2/2.3.7 librtmp/2.3 Release-Date: 2020-08-19 Protocols: dict file ftp gopher http imap ldap ldaps pop3 rtmp rtsp …

Linux workqueue介紹

Linux中的workqueue機制就是為了簡化內核線程的創建。通過調用workqueue的接口就能創建內核線程。并且可以根據當前系統的CPU的個數創建線程的數量&#xff0c;使得線程處理的事務能夠并行化。 工作隊列&#xff08;workqueue&#xff09;是另外一種將工作推后執行的形式。工作…

04:C語言流程控制

C語言流程控制 1、選擇結構1.1、第一種&#xff1a;if ...else / if ...else if...else1.2、第二種&#xff1a;switch case 2、循環結構2.1、第一種&#xff1a;for循環2.1、第二種&#xff1a;while循環2.2、第三種&#xff1a;do...while循環 在C語言程序里&#xff0c;一共…

為什么要考數據庫證書?

考取數據庫證書有多方面的理由和好處&#xff0c;這些好處不僅限于個人職業發展&#xff0c;也涉及到提升專業技能、增強競爭力以及獲得行業認可等方面。以下是一些主要的原因&#xff1a; 提升專業技能&#xff1a;數據庫證書考試通常要求考生掌握一定的數據庫理論知識和實踐技…

Java數據結構9-排序

1. 排序的概念及引用 1.1 排序的概念 排序&#xff1a;所謂排序&#xff0c;就是使一串記錄&#xff0c;按照其中的某個或某些關鍵字的大小&#xff0c;遞增或遞減的排列起來的操作。 穩定性&#xff1a;假定在待排序的記錄序列中&#xff0c;存在多個具有相同的關鍵字的記錄…

【vuejs】vue-router多層級路由配置以及頁面嵌套的處理

1. 多層級頁面嵌套概念 1.1 什么是多層級頁面嵌套 多層級頁面嵌套指的是在單頁面應用&#xff08;SPA&#xff09;中&#xff0c;頁面結構由多個嵌套的組件組成&#xff0c;每個組件可能代表不同的頁面或頁面區域。這種結構允許開發者將應用組織成多個模塊&#xff0c;每個模…

認證資訊|Bluetooth SIG認證

在當今高度互聯的世界中&#xff0c;無線技術的普及已經成為我們生活和工作中不可或缺的一部分。作為領先的無線通信技術之一&#xff0c;Bluetooth技術以其穩定性、便捷性和廣泛的應用場景而備受青睞。然而&#xff0c;要想在激烈的市場競爭中脫穎而出&#xff0c;獲得Bluetoo…

6、Redis系統-數據結構-04-Hash

四、哈希表&#xff08;Hashtable&#xff09; 哈希表是一種高效的鍵值對數據結構&#xff0c;通過散列函數將鍵映射到表中的位置&#xff0c;實現快速的插入、刪除和查找操作。Redis 廣泛使用哈希表來實現 Hash 對象和數據庫的鍵值存儲。以下將從結構設計、哈希沖突與鏈式哈希…

深入源碼,探究#、$號替換符的區別

在Mybatis的日常使用過程中以及在一些技術論壇上我們都能常常聽到&#xff0c;不要使用$符號來進行SQL的編寫&#xff0c;要使用#符號&#xff0c;否則會有SQL注入的風險。那么&#xff0c;為什么在使用$符號時會有注入的風險呢&#xff0c;以及#號為什么不會有風險呢&#xff…