---
title: "什麼是 Solidity 中的 modifier？"
description: "Solidity Modifier 的作用、運作方式，以及何時該使用"
---

# 什麼是 Solidity 中的 modifier？

[Solidity](https://www.alchemy.com/overviews/solidity) 是一種物件導向的高階語言，用於實作智慧合約。在[學習 Solidity](https://ethereum.stackexchange.com/questions/55048/modify-struct-on-upgradeable-smart-contracts?rq=1) 的過程中，你會遇到修飾器（modifier），這是一種特殊類型的函式，用來修改其他函式的行為。

在本文中，我們將說明 Solidity 修飾器的作用、介紹修飾器的類型，並示範如何使用它們。讀完本文後，你將能夠辨識 Solidity 修飾器並理解如何使用它們。

## **Solidity 修飾器的作用是什麼？**

**修飾器是一種特殊的[ Solidity 函式類型](https://www.alchemy.com/overviews/solidity-functions)，用來修改其他函式的行為。**舉例來說，開發者可以使用修飾器，在允許函式執行之前檢查是否滿足某個條件。

修飾器與函式類似，可以接受參數並具有回傳型別。修飾器也可以串連使用，也就是說一個函式上可以套用多個修飾器。

不過，修飾器只能修改合約邏輯，[無法修改合約的儲存空間](https://ethereum.stackexchange.com/questions/55048/modify-struct-on-upgradeable-smart-contracts?rq=1)，包括結構體（struct）在內。修飾器能減少開發者需要撰寫的樣板程式碼，並讓 Solidity 程式碼更易讀。

### **Solidity 函式可以套用多個修飾器嗎？**

**可以，開發者可以在單一 Solidity 函式上使用多個修飾器。**多個修飾器之間以逗號分隔。使用多個修飾器時，有一點需要注意：修飾器的順序很重要。清單中第一個修飾器會先被執行，第二個修飾器接著被套用，依此類推。

舉例來說，如果你有一個修飾器用來檢查使用者是否已通過驗證，另一個修飾器用來檢查使用者是否有權限查看某個資源，那麼這些修飾器套用的順序，將決定使用者最終能否查看該資源。

## **Solidity 修飾器有哪些不同類型？**

**Solidity 修飾器大致可分為四類：閘門檢查（gate check）、前置條件（prerequisite）、過濾器（filter），以及重入攻擊防護（reentrancy attack prevention）。**

### **1. 閘門檢查**

「閘門檢查」是一種修飾器，會在允許函式執行前，檢查某個條件是否成立。

舉例來說，假設你有一個函式讓使用者可以從帳戶提款，但在函式執行前，開發者可能想先檢查使用者的帳戶餘額是否足夠進行提款。這種檢查就被視為閘門檢查修飾器。

另一個閘門檢查的例子，是在允許使用者查看某項資源前，先檢查使用者是否已通過驗證。

### **2. 前置條件**

「前置條件」是一種修飾器，用於為函式執行設定好環境，而不是檢查某個條件是否成立。

舉例來說，Solidity 開發者可能會使用一個函式，要求呼叫時必須連同傳送一定數量的 Ether 才能執行。在這種情況下，前置條件就是負責設定 Ether 餘額的函式。

### **3. 過濾器**

「過濾器」是一種修飾器，會檢查某個條件是否成立，若成立，就允許函式執行。若條件不成立，函式就不會執行。

與閘門檢查不同的是，即使條件成立，閘門檢查也不會自動允許函式執行；而過濾器則會在條件成立時允許函式執行。

### **4. 重入攻擊防護**

**[重入攻擊](https://www.alchemy.com/overviews/reentrancy-attack-solidity)是一種攻擊方式，惡意行為者試圖透過遞迴呼叫多次執行某個函式，藉此進行利用。**

舉例來說，假設你有一個函式讓使用者可以從帳戶提款。重入攻擊者可能會嘗試多次呼叫該函式，藉此提領超過其帳戶實際餘額的金額。

為了防止重入攻擊，你可以使用修飾器來檢查該函式是否正被遞迴呼叫。若是，函式就不會執行。

## **require 與 Solidity 修飾器之間的關係是什麼？**

**require 經常與修飾器互換使用，因為兩者都能讓你在允許函式執行前，[檢查某個條件是否成立](https://www.alchemy.com/university/courses/solidity?a=313ac76819)。若指定的條件不成立，編譯器就會拋出錯誤。**

舉例來說，以下敘述使用了 require 關鍵字，讓只有擁有者才能與該函式互動：

require 與 Solidity 修飾器之間存在一些重要差異：

1. 修飾器可以用來為函式執行設定環境（如前置條件的情況）
1. _require_ 只能用來檢查某個條件是否成立
1. 修飾器可以被覆寫（override）
1. _require_ 不能被覆寫

## **Solidity 處理修飾器的方式與 Vyper 有何不同？**

Vyper 是一種以 Python 風格設計、用於 Ethereum 智慧合約開發的語言，為了提升安全性做出了一些取捨，其中包括[不使用修飾器](https://www.alchemy.com/overviews/solidity-vs-vyper)。取而代之，開發者需在函式內使用內嵌的檢查與斷言（assert），而在修改智慧合約時，也需要再次以明確的方式將變更寫在函式中。

Vyper 選擇移除修飾器功能，提升了智慧合約的可稽核性，因為讀者不必在腦中將修飾器套用在函式上，才能理解該函式會執行什麼動作。

### **什麼是修飾器覆寫（modifier overriding）？**

關鍵字「virtual」可用來標示某個修飾器可以在衍生合約中被覆寫。舉例來說，假設你有一個合約「Base Contract」，其中有一個修飾器「myModifier」。你還有一個合約「Derived Contract」，它繼承自「Base Contract」。

如果「Base Contract」被標示為「virtual」，那麼它就可以在衍生合約中被覆寫。這種做法常見於函式庫的情境中，讓合約具備可自訂性。

### **修飾器如何與繼承機制配合運作？**

**繼承讓你能夠擴充合約的屬性與特性，而在修飾器的情境中，繼承讓你可以新增修飾器，或覆寫既有的修飾器。**這可以透過前一節提到的 _virtual_ 關鍵字來實現。

以下這個簡單的實作範例，展示了繼承與修飾器如何協同運作：

在這個範例中，合約 B 繼承自合約 A。兩個合約都有一個名為「X」的修飾器。不過，在合約 B 中，這個修飾器被標示為「override」，表示它覆寫了合約 A 中的修飾器。

## **如何在 Solidity 中使用修飾器**

要使用修飾器，首先需要在合約中定義修飾器函式。修飾器會使用一個特殊符號「\_;」，只有在修飾器的條件被滿足時，才會插入函式主體。

**以下合約示範了如何使用修飾器：**

在上面的範例中，該合約有兩個修飾器：「onlyOwner」與「costs」。

第一個修飾器會檢查 _msg.sender_ 是否為合約擁有者，第二個修飾器則檢查 _msg.value_ 是否大於或等於某個特定價格。

這兩個修飾器都可以套用在合約中的任何函式上。

## **繼續學習 Solidity 修飾器**

修飾器是用來修改其他函式行為的函式。透過使用修飾器，你可以減少需要撰寫的樣板程式碼，並讓你的 Solidity 程式碼更易讀。

若想[繼續學習 Solidity 修飾器](https://www.alchemy.com/overviews/learn-solidity)，並了解如何成為 Solidity 開發者，歡迎報名 Alchemy University 為期 7 週的 Ethereum Developer Bootcamp。這個由 ChainShot 團隊原創、完全免費的 [Solidity 速成課程](https://www.alchemy.com/university/courses/solidity?a=313ac76819)，是學習 Solidity 的最佳途徑。如果開發者對開發領域完全陌生，Alchemy University 為期 **3 週的 JavaScript 速成課程**，會是在開始 Ethereum bootcamp 之前很好的先修課程。
