智能合約開發
函數修飾子
修飾子是一個可重複使用的包裝,你把它標在函數上,以在函數本體之前(或之後)執行共用的檢查。教科書範例是 onlyOwner:把「你是擁有者嗎?」的檢查寫成一個修飾子一次,然後貼到每個有特權的函數上,而不必在每個函數裡複製貼上相同的 require。
機制的關鍵是修飾子本體裡的單一佔位符 _;。寫在 _ 之前的一切作為前置條件執行(通常是 require 檢查);底線精確標出被包裝函數自身本體被嵌入的位置;寫在 _ 之後的則作為後置條件執行。編譯器實際上會把修飾子的程式碼內聯進每一個被它修飾的函數,所以一個沉重的修飾子會在每個使用點各自增加一次部署的位元組碼大小。當數個修飾子疊在同一個函數上時,它們由左至右巢狀,各自在其底線處包住下一個。
修飾子非常適合橫切關注點:存取控制、重入防護(在 _ 之前上鎖、之後解鎖)以及暫停開關。有兩個陷阱很重要。第一,若修飾子的 _; 無法被觸及(例如被擋在 return 之後),會默默讓函數本體永遠不執行——這是危險又容易忽略的錯誤。第二,由於本體被內聯,過於龐大的修飾子邏輯會讓每個被修飾的函數膨脹;對沉重的檢查,通常更乾淨的做法是從一個輕薄的修飾子內部呼叫一個內部輔助函數。
modifier onlyOwner() {
require(msg.sender == owner, "not owner");
_; // the wrapped function body runs here
}
function setFee(uint256 f) external onlyOwner { fee = f; }守衛寫一次,到處重用。
若修飾子可能在沒碰到 _; 的情況下抵達結尾,它會完全跳過函數本體卻仍「成功」回傳。務必確保底線是可被觸及的。
另见