solidity基础知识
1、solidity是一種語法類似JavaScript的高級語言,它被設計成以編譯的方式生成以太坊虛擬機代碼。在后續的內容中你將會發現,使用它很容易創建用于投票、眾籌、封閉拍賣、多重簽名錢包等等的合約。
solidity在線IDE:https://ethereum.github.io/browser-solidity/#optimize=false&version=soljson-v0.4.23+commit.124ca40d.js
2、智能合約
智能合約(Smart Contract)是一種旨在以信息化方式傳播、驗證或執行合同的計算機協議。只能合約允許在沒有第三方的情況下進行可信交易。這些交易可追蹤不可逆轉。智能合約概念于1994年由Nick Azabo首次指出。
智能合約的目的是提供優于傳統合同方法的安全,病減少與合同相關的其他成本交易。
3、以太坊虛擬機
以太坊虛擬機(EVM)是以太坊中只能合約的運行環境。它不僅被沙箱封裝起來,事實上它被完全隔離,也就是說EVM內部的代碼不能尋呼機到網絡、文件系統或者其他進程。甚至只能合約與其它只能合約只有有限的接觸。
3.1、賬戶
以太坊有兩類賬戶。他們共用同一個地址 空間。外部賬戶,該賬戶被公鑰-私鑰對控制(人類)。合約賬戶,該類賬戶被存儲在賬戶中的代碼控制。
外部賬戶由公鑰決定;合約賬戶在創建合約時確定(由合約創建者地址+該地址發出過得交易數量計算。地址發出過的交易數量也被稱為nonce);合約賬戶存儲代碼。
另外,每個賬戶都有一個以太幣余額(單位wei),該賬戶余額可以通過向它發送帶有以太幣的交易來改變。
3.2、交易
交易是一條消息,從一個賬戶發送得到另一個賬戶(可能是相同的賬戶或者零賬戶)。交易可以包含二進制數據(payload)和以太幣。
另外,如果目標賬戶零賬戶(賬戶地址是零),交易將創建一個新合約。即創建合約也是一個交易的過程,只是目標賬戶是0.
3.3、Gas
以太坊上的每筆交易都會收取一定數量的gas,gas的目的是限制執行交易所需的工作量,同時為執行支付費用。當EVM執行交易時,gas將按照特定規則被逐漸消耗。
gas price (以太幣計)是由交易創建者設計的,發送賬戶需要預付的交易費用 = gas price * gas amount。如果執行結束還有剩余,這些gas將被返還給發送賬戶。
無論執行到什么位置,一旦gas被消耗盡,將會觸發一個out-of-gas異常。當前調用幀所做的所有狀態修改都將被回滾。
3.3 存儲、主存和棧
每個賬戶有一塊持久化區域被稱為存儲,其形式為key-value,key和value的長度均為256比特。在合約里,不能遍歷賬戶的存儲。相對于另外兩種,存儲的讀操作開銷較大,修改存儲更甚。一個合約只能對它自己的存儲進行讀寫。
第二內存區被稱為主存。合約執行每次消息調用時,都有一塊新的,被清除過得主存。主存可以以字節粒度尋址,但是讀寫粒度為32字節(256比特)。操作主存的開銷隨著其增長而變大(平方級別)。
EVM不是基于寄存器,而是基于棧的虛擬機,因此所有的計算都在一個被稱為棧的區域執行。棧最大有1024個元素,每個元素256比特,對棧的訪問只限于其頂端,方式為:允許拷貝最頂端的16個元素中的一個到棧頂,或者交換棧頂元素和下面16個元素中的一個。所有其他操作都只能取最頂的兩個(或者一個、更多)元素,并把結果壓在棧頂。當然可以把棧上的元素放到存儲或者主存中,但是無法訪問棧上指定深度的那個元素,在那之前必須要把指定深度之上的所有元素從棧中移除才行
3.4、指令集
EVM的指令集被刻意保持在最小規模,以盡可能避免可能導致共識問題的錯誤實現。所有的指令都是針對256比特這個基本的數據類型的操作。具備常用的算術,位,邏輯和比較操作。也可以做到條件和無條件跳轉。此外,合約可以訪問當前區塊的相關屬性,比如它的編號和時間戳。
3.5、消息調用
合約可以通過消息調用的方式來調用其它合約或者發送以太幣到非合約賬戶。消息調用和交易非常類似,它們都有一個源,一個目標,數據負載,以太幣,gas和返回數據。事實上每個交易都可以被認為是一個頂層消息調用,這個消息調用會依次產生更多的消息調用。
一個合約可以決定剩余gas的分配。比如內部消息調用時使用多少gas,或者期望保留多少gas。如果在內部消息調用時發生了out-of-gas異常(或者其他異常),合約將會得到通知,一個錯誤碼被壓在棧上。這種情況只是內部消息調用的gas耗盡。在solidity中,這種情況下發起調用的合約默認會觸發一個人工異常。這個異常會打印出調用棧。就像之前說過的,被調用的合約(發起調用的合約也一樣)會擁有嶄新的主存并能夠訪問調用的負載。調用負載被存儲在一個單獨的被稱為calldata的區域。調用執行結束后,返回數據將被存放在調用方預先分配好的一塊內存中。
調用層數被限制為1024,因此對于更加復雜的操作,我們應該使用循環而不是遞歸。
3.6、代碼調用和庫
存在一種特殊類型的消息調用,被稱為callcode。它跟消息調用幾乎完全一樣,只是加載目標地址的代碼將在發起調用的合約上下文中運行。這意味著一個合約可以在運行時從另外一個地址動態加載代碼。存儲當前地址和余額都指向發起調用的合約,只有代碼是被調用地址獲取的。
這使得solidity可以實現庫。可服用的庫代碼可以應用在一個合約存儲上,可以用來實現復雜的數據結構。
3.7、日志
在區塊層面,可以用一種特殊的可索引的數據界都來存儲數據。這個特性被稱為日志,solidity用它來實現事件。合約創建之后就無法訪問日志數據,但是這些數據可以從區塊鏈外高效的訪問。因為部分日志數據被存儲在布隆過濾器中,我們可以高效并且安全地搜索日志,所以那些沒有下載整個區塊鏈的網絡節點(輕客戶端)也可以找到這些日志。
3.8、創建
合約甚至可以通過一個特殊的指令來創建其他合約(不是簡單的向零地址發起調用)。創建合約的調用跟普通的消息調用的區別在于,負載數據執行的結果被當做代碼。調用者/創建者在棧上得到新的合約。
3.9、自毀
只有在某個地址的合約執行自毀操作時,合約代碼才會從區塊鏈上移除。合約地址上剩余的以太幣會發送給指定目標,然后其存儲和代碼被移除。
4、語法
4.1、引入源文件
源文件包括任意數量的合約定義和include指令
solidity支持import語句。
在全局層次上,可以這樣用:
(1)import "filename";將會從“filename”
(2)**import** ****** as symboName from "filename" 創立一個全局的符號名為sumbolName,其中的成員來自filename的所有符號
(3)import {symbol as alias,symbol2} from "filename";將創立一個新的全局變量別名:alias和symbol2,它將分別從filename引入symbol1和symbol2
(4)import "filename" as symbolName;//推薦使用 等價于 import * as symbolName from "filename"
路徑:
(1)在上面,文件名總是用/作為目錄分隔符,.是當前的目錄,..是父目錄,路徑名稱不用.開頭的都將視為絕對路徑。
(2)從同一個目錄下import一個文件夾x作為當前文件,用import "./x" as x;如果使用import "x" as x;是不同的文件引用(在全局中使用“include directory”)
(3)import "x" as X 是不同的文件引用(在全局中使用“include directory”)。
(4)它將依賴于編譯器(見后)來解析路徑。通常,目錄層次不必嚴格限定映射到你的本地文件系統,它也可以映射到ipfs,http或git上的其他資源
4.2、注釋
//單行注釋和多行注釋(/../)
有種特別的注釋叫做“natspec”(文檔以后寫出來),在函數聲明或定義的右邊用三個斜杠(///)或者用兩個型號(/*.../).如果想要調用一個函數,可以使用doxygen-style標簽里面文檔功能,形式驗證,并提供一個確認條件的文本注釋顯示給用戶。
4.3、 類型
solidity是一種靜態類型語言,意思是每個變量(聲明和本地)在編譯時刻都要定義(或者至少要知曉,參看后面的類型導出)。solidity提供幾個基本類型組合成復雜類型。
(1)變量類型
以下類型被叫做值類型,因為這些類型的變量總是要被賦值,作為函數參數或者在賦值中,總需要拷貝。
布爾類型
布爾:bool 值是true和false
操作符:!(邏輯非)、&&(邏輯與)、||(邏輯或)、==(相等)、!=(不等)。
操作符||和&&可以應用常規短路規則,||如果一邊為true,另一邊不用計算,&&如果一邊為false,另一邊不用計算。
整型:int和uint,有符號和無符號的整數,關鍵字uint8到uint256步長8(從8到256位的無符號整數)。uint和int分別是uint256和int256的別名。
操作符:比較(<=,<,==,!=,>=,>計算布爾量),位操作符(&,|,^(位異或),~(位取反)),算術操作符(+,-,一元-,一元+,*,/,%(取余數),**(冪次方)).
地址成員:address,可以轉賬和查詢余額(balance、send、transfer。
注解:如果x是合約地址,它的代碼將和send調用一起執行(這是EVM的限制,不能修改),如果gas用完或者失敗,ether轉移將被回退,這種情況下,send返回false。
調用(call)和調用碼(callcode):調用這兩個函數將會返回true或false。callcode的目的是使用庫代碼存儲在另一個合同。用戶必須要確保存儲在兩個合約的布局適用于callcode。這兩個函數是非常低級的函數,它可以作為打破solidity的類型安全的最后手段。
(2)引用類型
復雜類型,拷貝復雜類型可能相當耗費存儲?時間,我們必須考慮把他們存儲在內存(這不是持久化)或者存儲器(狀態變量存儲的地方)
函數返回參數存儲在內存,局部變量默認是存儲在存儲器里面。
(3)數據存儲位置:內存、存儲器、calldata
外部函數的參數(無返回):calldata
狀態變量:存儲器
默認數據存儲位置
函數(有返回)的參數:內存
其他局部變量:存儲器。
注意存儲在不同位置的變量不能直接賦值。
內存與內存、存儲器和存儲器之間賦值是引用賦值 ,值會改變,其他是拷貝,不會改變值。
(4)數組
數組可以是固定大小的,也可以是動態的,對于存儲器數組來說,成員類型可以是任意的(也可以是其他數組、映射或結構)。對于內存數組來說,成員類型不能是一個映射;如果是公開可見的函數參數,成員類型是必須是ABI類型的。
動態數組:string[] str;
定長數組:string[3] str;
bytesh和string是特殊類型的數組。bytes類似于byte[],但它是緊湊排列在calldata里的。string等于bytes,但不允許用長度或索引訪問。同時如果想要訪問字符串s的某個字節,要使用bytes(s).length/bytes(s)[7] = "x";記住,你正在訪問的低級utf - 8字節表示,而不是單個字符!
成員:
length:數組數量。數組長度一旦確定,如果訪問長度以外的數據,會報錯,如果刪除數組里面的數據,要手動調整長度,和數據位置。因為刪除只是把值初始化,并沒有刪除。
push:在數組尾部添加數據。
注意:到目前為止還不可以在外部函數中使用數組的數組。由于EVM的局限,合約函數f contract C { function f() returns (uint[]) { ... } }不可能從外部函數調用返回動態的數組(不能返回數組),使用web3.js調用,將有返回值,但是使用solidity調用,就沒有返回值。
(5)結構體
struct shape{uint height;uint width;} 函數賦值 shape(1,2).結構體內部可以包含任何類型的數據,但是不能包含它自己。也就是不能把自己作為自己的成員。
(6)映射(mapping)
一種鍵值對的映射關系存儲結構。定義方式為mapping(_KeyType => _KeyValue).鍵的類型允許除映射外的所有類型。值的類型無限制。映射可以視為一個哈希表,其中所有可能的鍵已被虛擬化的創建,被映射到一個默認值(二進制表示的零)。但在映射表中,我們并不存儲鍵的數據,僅僅存儲它的keccak256哈希值,用來查找時使用。所以映射沒有長度。mapping(address => uint) public balances;添加數據balance[msg.sender]=msg.value;
(7)刪除delete(參考:http://baijiahao.baidu.com/s?id=1566265348199485&wfr=spider&for=pc)
delete用于釋放空間,釋放空間將會返還一些gas。
刪除基本類型將他們的值設置為初始值。刪除枚舉時,會將其值重置為序號0的值。不能刪除函數,刪除結構體會將結構體里面的變量都設置為初始值,刪除映射會報錯,不過可以刪除里面的某一項。刪除十足試講數組的所有元素設置為0.
刪除本質是對一個變量賦初值。所以我們刪除storage的引用時會報錯,因為storage的引用并沒有自己已分配的存儲空間,所以不能對storage的引用直接賦初值。
(8)類型轉換
隱式轉換:如果一個操作符應用于不同類型,編譯器就會試圖隱式把操作數的類型,從一種類型轉換到其他類型。一般來說,一個隱式的值類型之間的轉換時可能的,如果予以敏感的話,信息不回丟失;int8可轉成int16,int256等等,但是int8不能轉成uint256,因為uint256范圍不包含int8部分內容。
顯示轉換:int8 a = 2;uint b = uint(a);如果一個類型是顯式地轉換為一個更小的類型,高階位將被移除.
(9)單位(參考:https://blog.csdn.net/wo541075754/article/details/79049425)
以太單位:wei、finney、szabo、ether,以太幣數量默認缺省單位是wei。
1kwei(babbage) = 1e3wei (e就是乘以10的3次方)
1Mwei(lovelace) = 1e6wei; 1Gwei(shannon) = 1e9; 1microether(szabo) = 1e12; 1milliether(finney) = 1e15wei; 1ether = 1e18wei;
時間單位:now獲取系統當前時間,類型是int,沒有日期:1 seconds;minutes ,hours ,days,weeks,years等
如果你使用這些單位執行日歷計算,要注意以下問題。 因為閏秒,所以每年不總是等于365天,甚至每天也不是都有24小時,。由于無法預測閏秒,一個精確的日歷庫必須由外部oracle更新。
(10)特殊的變量和函數
有特殊的變量和函數總是存在于全局命名空間,主要用于提供關于blockchain的信息。
塊和交易屬性:
block.coinbase (address): :當前塊的礦工的地址
block.difficulty (uint):當前塊的難度系數
block.gaslimit (uint):當前塊汽油限量
block.number (uint):當前塊編號
block.blockhash (function(uint) returns (bytes32)):指定塊的哈希值——最新的256個塊的哈希值
block.timestamp (uint):當前塊的時間戳
msg.data (bytes):完整的calldata
msg.gas (uint):剩余的汽油
msg.sender (address):消息的發送方(當前調用)
msg.sig (bytes4):calldata的前四個字節(即函數標識符)
msg.value (uint):所發送的消息中wei的數量
now (uint):當前塊時間戳(block.timestamp的別名)
tx.gasprice (uint):交易的汽油價格
tx.origin (address):交易發送方(完整的調用鏈)
由于所有塊可伸縮性的原因,(所有)塊的hash值就拿不到,你只能訪問最近的256塊的hash值,其他值為零。
(11)數學和加密功能
addmod(uint x,uint y,uint z) return (uint) 計算(X+y)%z
mulmod(uint x,uint y,uint z) return (uint)計算(X*y)%z
加密數據
sha3(……) returns (byte32);
sha256(……) returns (byte32);
(12)自毀
selfdestruct(address);銷毀當前合約,其資發送給指定的地址。此外,當前合同的所有函數可以被直接調用(包括當前函數)
4.4、表達式和控制結構
(1)控制結構:
除了 switch和goto,solidity的絕大多數控制結構均來自于C / JavaScript,if, else, while, for, break, continue, return, ? :, 的語義均和C / JavaScript一樣。
條件語句中的括號不能省略,但在單條語句前后的花括號可以省略。
(2)函數調用
內部函數調用:直接調用函數;
外部函數調用:外外部調用函數,參數必須存儲到內存中,特別注意的是合約構造函數中不能用this調用函數。因為當前合約還沒有創建。如果直接調用合約名,而不實例化,那么合約并不執行構造函數,
具名參數調用:可以直接調用,按照順序輸入值,也可以({參數:值,})
函數返回可以返回多個類型不一樣的值。支持返回元組類型。
(3)異常
有一些自動拋出異常的情況(見下文)。您可以使用throw 指令手動拋出一個異常。異常的影響是當前執行的調用被停止和恢復(即所有狀態和余額的變化均沒有發生)。另外, 異常也可以通過Solidity 函數 “冒出來”, (一旦“異常”發生, 就send "exceptions", call和callcode底層函數就返回false)。
捕獲異常是不可能的。
目前,Solidity異常自動發生,有三種情況,:如果你訪問數組超出其長度 (即x[i]wherei >= x.length);如果一個通過消息調用的函數沒有正確的執行結束(即gas用完,或本身拋出異常);如果一個庫里不存在的函數被調用,或Ether被發送到一個函數庫里。
異常還會通過solidity的函數調用向上冒泡(bubbled up)傳遞。(send,和底層的函數調用call,delegatecall,callcode是一個例外,當異常發生時,這些函數返回false)。
通過assert判斷內部條件是否達成,require驗證輸入的有效性。這樣的分析工具,可以假設正確的輸入,減少錯誤。這樣無效的操作碼將永遠不會出現。(返回值是false)
5、合約
合約是面向對象語言的類,他們持久存放在狀態變量和函數中,可以修改這些變量。合約在創建時,構造函數將被調用。
(1)可見性和修飾符
函數調用分為內部調用和外部調用,內部調用不創建一個真實的EVM調用,也稱為消息調用,外部調用需要創建一個真實的EVM調用。
函數修飾符有external、public、internal、private,缺省是public。對狀態變量而言,external是不可能的,默認是internal。
external:外部函數是合約接口的一部分,這意味著他們可以從其他合約調用,也可以通過事務調用。如果在本合約調用external,要像外部合約調用這個函數一樣,不能直接調用。external和public 修飾函數,外部函數都可以訪問,但是external更省gas。
public:公共函數是合約接口的一部分,可以通過內部調用或通過消息調用。對公共狀態變量而言,會有的自動訪問修飾符的函數生成(如果一個狀態變量用public修飾,合約將會自動給這個變量生成get函數,獲取這個變量,需要調用get方法)
internal:這些函數和狀態變量只能內部訪問(即當前合約或由它派生的合約),而不使用(關鍵字)this
private:私有函數和狀態變量僅僅在定義該合約中可見,在派生的合約中不可見。
注意:
在外部觀察者中,合約的內部的各項均可見。用private僅僅防止其他合約來訪問和修改(該合約中)信息。但它對blockchain之外的整個世界仍然可見。
可見性說明符是放在狀態變量的類型之后,(也可以放在)參數列表和函數返回的參數列表之間。
(2)函數修飾符(modifier)
修飾符可以用來輕松改變函數的行為。列如,在執行的函數之前自動檢查條件。他們是可繼承合約的屬性,也可被派生合約重寫。(可以封裝一些條件等等,或者封裝重復使用的代碼,一個函數可以使用多個修飾符,使用空格格開)
(3)常量(constant)
(4)回退函數(callback)
一個合約可以有一個匿名函數。若沒有其他函數和給定法人函數標識符一致的話,該函數將沒有參數,將執行一個合約的調用(如果沒有提供數據)。
1)當合約接收一個普通的ether時,函數將被執行(沒有數據)。在這樣一個情況下,幾乎沒有gas用于函數調用,所以調用回退函數是非常廉價的,這點非常重要。
2)當合約收到ether時(沒有任何其它數據),這個函數也會被執行。為了接收ether,回退功能必須標記為應付款。如果不存在此類功能,則合約無法通過正常交易接收ether。
3)一個沒有定義一個回退函數的合約。如果接收ether,會觸發異常,并返還ether(solidity v0.4.0開始)。所以合約要接收ether,必須實現回退函數。在部署合約到網絡前,保證透徹的測試你的回退函數,來保證函數執行的花費控制在2300gas以內.
(5)事件
事件允許EVM寫日志功能的方便使用,進而在dapp的用戶接口中用javascript順序調用,從而監聽這些事件。
事件是合約可繼承的成員。當他們調用時,會在導致一些參數在事務日志上的存儲--在blockchain上的一種特殊的數據結構。這些日志和合約的地址相關聯,將納入blockchain中,存儲在block里以便訪問(在Frontier和Homestead里是永久存儲,但在Serenity里有些變化)。在合約內部,日志和事件數據是不可訪問的(從創建該日志的合約里)
事件的參數中,如果參數被設置為indexed(最多只有三個參數可以設置indexed),來設置是否索引,設置索引后,可以允許通過這個參數來查找日志,甚至可以按特定的值過濾。
如果參數增加indexed,存儲到日志中的topic部分,如果事件參數對應的參數值只是單個值, 就是正常的存儲(存儲達到日志的topic部分),如果事件參數對應的參數值是一個數組類型,因為數組類型這種復雜類型的長度不確定,先轉換成了哈希值。
如果參數不增加indexed,存儲到日志的data部分。
日志中存儲的不同的索引事件就叫不同的主題。比如,事件定義,event transfer(address indexed _from, address indexed _to, uint value)有三個主題,第一個主題為默認主題,即事件簽名transfer(address,address,uint256),但如果是聲明為anonymous的事件,則沒有這個主題;另外兩個indexed的參數也會分別形成兩個主題,可以分別通過_from,_to主題來進行過濾。如果數組,包括字符串,字節數據做為索引參數,實際主題是對應值的Keccak-256哈希值。
(6)繼承(is)
solidity支持多重繼承,除非合約時顯式給出的,所有的函數調用都是虛擬的,絕大多數派生函數可被調用。即使合約繼承了多個其他的。
子類可以訪問public、internal權限控制的變量和函數。在子類中可以訪問狀態變量,因為狀態變量默是internal的。
1)繼承支持傳參,如果父類構造函數有參數,繼承時 is Base(1)
方法二:
contract Base{
uint a;
function Base(uint _a){
a = _a;
}
}
contract InheritParaModifier is Base{
function InheritParaModifier(uint _a) Base(_a * _a){}
function getBasePara() returns (uint){
return a;
}
}
View Code
如果要傳入到基類的是簡單的常量,第一種方式會更加簡潔。但如果傳入的參數與子類的輸入參數有關,那么你應該使用第二種方式,以獲取參數值。如果你同時使用了這兩種方式,后一種方式將最終生效。
2)多繼承會出現幾個問題,如菱形繼承問題(鉆石問題),所以多繼承要注意繼承的順序。同時如果繼承的合約中擁有相同名字不同類型的方法或者變量,會視為錯誤。所以建議使用單繼承。
(7)抽象(沒有關鍵字,只是沒有方法體的合約會視為抽象合約)
如果一個合約從一個抽象合約里繼承,但卻沒實現所有函數,那么它也是一個抽象合約。
(8) 接口(interface)
接口與抽象合約類似,與之不同的是,接口內沒有任何函數是已實現的,同時還有如下限制: .不能繼承其它合約,或接口;不能定義構造器 ;.不能定義變量 ;不能定義結構體 ;.不能定義枚舉類。
(9)庫(library)
庫與合約類似,但它的目的是在一個指定的地址,且僅部署一次,然后通過EVM的特性DELEGATECALL來復用代碼。這意味著庫函數調用時,它的代碼是在調用合約的上下文中執行。使用this將會指向到調用合約,而且可以訪問調用合約的存儲(storage)。因為一個合約是一個獨立的代碼塊,它僅可以訪問調用合約明確提供的狀態變量(state variables),否則除此之外,沒有任何方法去知道這些狀態變量。(調用同目錄下本地庫(./libraryName.sol))
對比普通合約來說,庫的限制: 無狀態變量(state variables)。 不能繼承或被繼承 不能接收ether。
庫的常見―”坑” msg.sender 的值msg.sender 的值將是調用庫函數的合約的值。 例如,如果 A 調用合約 B,B 內部調用庫 C。在庫 C 庫的函數調用里,msg.sender 將是 合約 B 的地址。 表達式 LibraryName.functionName() 用 CALLCODE 完成外部函數調用, 它映射到一 個真正的EVM調用,就像otherContract.functionName() 或者 this.functionName()。 這種調用可以一級一級擴展調用深度(最多 1024 級),把 msg.sender 存儲為當前的調 用者,然后執行庫合約的代碼,而不是執行當前的合約存儲。這種執行方式是發生在一個完 全嶄新的內存環境中,它的內存類型將被復制,并且不能繞過引用。 轉移 Ether原則上使用 LibraryName.functionName.value(x)()來轉移 Ether。但若使用 CALLCODE,Ether 會在當前合約里用完。
1)指令 using A for B;可用于附加庫函數(從庫A)到任何類型(B)。這些函數將收到一個作為第一個參數的對象(像Python中self變量)。
using A for *;,是指函數從庫A附加到任何類型。
在這兩種情況下,所有的函數將被附加,(即使那些第一個參數的類型與對象的類型不匹配)。該被調用函數的入口類型將被檢查,并進行函數重載解析。
6、修飾符
修飾符
constant for state variables:不允許賦值(除了初始化),不占用存儲塊。
constant for functions:不允許改變狀態- 這個目前不是強制的。
anonymous for events:不能將topic作為事件指紋進行存儲。
函數可以聲明view,在這種情況下他們保證不修改狀態。(以下聲明被視為修改狀態: 1).寫入狀態變量。 2).發送事件。 3).創建其他合同。 4).使用selfdestruct。 5).通過電話發送以太。 6).調用任何未標記為view或pure的函數。 7).使用低級別呼叫。 8).使用包含某些操作碼的內聯匯編。.
)
函數可以聲明為pure,在這種情況下,它們無權讀取或者修改狀態。(除了上面解釋的狀態修改語句列表之外,以下內容被認為是從狀態中讀取的: 1).從狀態變量讀取 2).訪問this.balance或<address> .balance。 3).訪問塊,tx,msg的任何成員(msg.sig和msg.data除外)。 4).調用任何未標記為pure的函數。 5).使用包含某些操作碼的內聯匯編。
)
assert(bool condition);//用于判斷內部錯誤,條件不滿足時拋出異常
require(bool condition);//用于判斷條件或外部組件錯誤,條件不滿足時拋出異常
revert();終止執行并還原改變的狀態
7、雜項
(1)命名,私有函數和參數用_開始來命名。
總結
以上是生活随笔為你收集整理的solidity基础知识的全部內容,希望文章能夠幫你解決所遇到的問題。