原文標題:《Solidity 極簡入門:3. 函數類型》
作者:0xAA
我最近在重新學solidity,鞏固一下細節,也寫一個「Solidity 極簡入門」,供小白們使用(編程大佬可以另找教程),每週更新1-3 講。
所有代碼開源在github:github.com/AmazingAng/WTFSolidity
Solidity 中的函數
solidity 官方文檔裡把函數歸到數值類型,但我覺得差別很大,所以單獨分一類。我們先看一下solidity 中函數的形式:
看著些複雜,咱們從前往後一個一個看(方括號中的是可寫可不寫的關鍵字):
1. function:聲明函數時的固定用法,想寫函數,就要以function 關鍵字開頭。
2. ():圓括號裡寫函數的參數,也就是要輸入到函數的變量類型和名字。
3. {internal|external|public|private} :函數可見性說明符,一共4 種。沒標明函數類型的,默認internal。
- public: 內部外部均可見,並且自動給stoage 變量生成getter 函數 。
- private: 只能從本合約內部訪問,繼承的合約也不能用。
- external: 只能從合約外部訪問(但是可以用this.f() 來調用,f 是函數名)
- internal: 只能從合約內部訪問,繼承的合約可以用。
4. [pure|view|payable]:決定函數權限/功能的關鍵字。 payable 很好理解,帶著它的函數,運行的時候可以給合約轉入ETH。 pure 和view 的介紹見下一節。
5. [returns ()]:函數返回的變量類型和名稱。
到底什麼是Pure 和View?
我剛開始學solidity 的時候,一直不理解pure 跟view 關鍵字,因為別的語言沒有類似的關鍵字。 solidity 加入這兩個關鍵字,我認為是因為gas fee。合約的狀態變量存儲在鏈上,gas fee 很貴,如果不改寫這些變量,就不用付gas。調用pure 跟view 的函數是不需要付gas 的。
我畫了一個馬里奧插畫,幫助大家理解。在插畫裡,我把合約中的狀態變量(存儲在鏈上)比作碧池公主,三種不同的角色代表不同的關鍵字。
WTH is pure and view in solidity?
pure,中文意思是「純」,在solidity 裡理解為「純純牛馬」。包含pure 關鍵字的函數,不能讀取也不能寫入存儲在鏈上的狀態變量。就像小怪一樣,看不到也摸不到碧池公主。
view,「看」,在solidity 裡理解為「看客」。包含view 關鍵字的函數,能讀取但也不能寫入狀態變量。類似馬里奧,能看到碧池,但終究是看客,不能入洞房。
不寫pure 也不寫view,函數既可以讀取也可以寫入狀態變量。類似馬里奧里的boss,可以對碧池公主為所欲為。
代碼
1. pure vs view
我們在合約裡定義一個狀態變量_number = 5。
定義一個add() function,每次調用,輸出_number + 1。
如果add() 包含了pure 關鍵字,例如function add() pure external,就會報錯。因為pure(純純牛馬)是不配讀取合約裡的狀態變量的,更不配改寫。那pure 函數能做些什麼?舉個例子,你可以給函數傳遞一個參數_number,然後讓他返回_number+1。
如果add() 包含view,比如function add() view external,也會報錯。因為view 能讀取,但不能夠改寫狀態變量。可以稍微改寫下方程,讓他不改寫_number,而是返回一個新的變量。
2. Internal vs External
我們定義一個internal 的minus() 函數,每次調用使得number 變量減1。由於是internal,只能由合約內部調用。我們再定義一個external 的minusCall() 函數,調用minus()。這樣,人們就能通過調用minusCall() 來間接調用internal 的minus()。
3. Payable
我們定義一個external payable 的minusPayable() 函數,間接的調用minus(),並且返回合約裡的ETH 餘額(this 關鍵字可以讓我們引用合約地址)。我們調用minusPayable() 時,往合約裡轉入1 個ETH。
我們可以在返回的信息中看到,合約的餘額是1 ETH。
總結
在第三講,我們介紹了solidity 中的函數類型,比較難理解的是pure 和view,在其他語言中沒出現過。 solidity 擁有pure 和view 兩種關鍵字主要是為了節省gas fee 和控制函數權限,這兩種方程都是不消耗gas 的。下一講我們會介紹引用和映射兩種類型,並介紹更複雜的函數。