---
title: "什麼是 Solidity 中的 function visibility？"
description: "了解 Public、External、Internal 和 Private Function Visibility 之間的差異"
---

# 什麼是 Solidity 中的 function visibility？

在 [Solidity](https://www.alchemy.com/overviews/solidity) 智能合約程式設計中，有一項機制能讓開發者根據指定的限制，決定誰或哪些其他智能合約可以呼叫自己的函式。這種定義[智能合約函式](https://www.alchemy.com/overviews/solidity-functions)可被如何互動的能力，稱為**函式可見性（function visibility）**。

## **什麼是函式可見性？**

Solidity 智能合約中的函式可見性功能，用來確保函式在指定時，其存取層級（包括 public、external、internal、private）能維持開發者原本的設計意圖。

如果開發者沒有使用正確的函式可見性類型，或程式碼中未指定可見性模式，合約預設的 public 可見性就會暴露在潛在可被利用的安全漏洞之下。除了未指定函式可見性所帶來的安全隱患之外，智能合約也可能無法如預期運作，因為函式會在缺乏正確指示的情況下運作。

### **誰可以呼叫智能合約函式？**

**能夠呼叫函式的合約有三種：主合約本身、繼承自主合約的合約（DerivedContract），以及第三方合約（OutsideContract）。**

[呼叫智能合約](https://www.alchemy.com/overviews/solidity-call)是指存取智能合約內的內部程式碼及其中包含的資料，這是一種從合約中取得資料的方式。

#### **1. 主合約（MainContract）**

以下是 MainContract 呼叫自身函式的語法：

#### **2. 繼承自主合約的合約（DerivedContract）**

以下是 DerivedContract 使用 MainContract 衍生函式的語法：

#### **3. 第三方合約（OutsideContract）**

以下是 OutsideContract 從外部函式呼叫主合約的語法。

## **函式可見性修飾符與繼承如何協同運作？**

**繼承是指使用「is」關鍵字，將一個合約的內容複製到另一個合約（「衍生合約」）中，函式修飾符的可見性會根據合約被指定的可見性類型，與衍生的子合約產生互動。**

函式可見性修飾符與繼承之間的關係說明如下：

- 若 _ParentContract_ 函式的修飾符為 **public**，_ChildContract_ 可以存取它。
- 若 _ParentContract_ 函式的修飾符為 **internal**，_ChildContract_ 可以存取它。
- 若 _ParentContract_ 函式的修飾符為 **private**，繼承的 _ChildContract_ 無法存取它。
- 若 _ParentContract_ 函式的修飾符為 **external**，繼承的 _ChildContract_ 無法存取它。

## **函式可見性修飾符如何協助節省 gas？**

由於 external 函式可見性修飾符的參數不會儲存到記憶體中，而是直接從 calldata 讀取，因此[智能合約消耗的 gas 較少](https://www.alchemy.com/overviews/solidity-gas-optimization)。相較之下，public 函式的輸入參數會儲存到記憶體中，這會導致部署智能合約時耗費更多 gas。

## **什麼是函式可見性修飾符？**

函式可見性修飾符共有四種類型，依可存取程度由高至低排列為：public、external、internal、private。開發者應根據希望誰能看到並呼叫該函式，來[修飾函式](https://www.alchemy.com/overviews/solidity-modifier)使用正確的可見性。

### **1. Public**

**public 函式可以被三種呼叫合約中的任何一種存取：主合約、衍生合約，以及第三方合約。函式預設即為 public。**

如上方程式碼範例所示，由於「public」的可見性，程式碼庫中任何合約都能存取「`functionPublic`」函式。

### **2. External**

**external 函式是只能由第三方呼叫的函式。**在 external 函式可見性下，能呼叫該函式的合約必須獨立於主合約之外，且不能是衍生合約。

上方是一個執行某項任務的隨機合約（`RandomContract`）。下方的程式碼片段是一個外部合約，正在呼叫 `RandomContract` 上的 external 函式。

### **3. Internal**

**internal 函式可以被主合約及其任何衍生合約呼叫。**internal 函式可以從最初宣告它們的主合約中存取，也可以透過繼承，被延伸自該主合約的合約存取。

### **4. Private**

**private 函式只能被指定它的主合約呼叫。**根據常見做法，private 函式通常會被優先使用，但如果所需的存取範圍比此修飾符類型更廣，則應改用其他合適的修飾符。

### **Solidity 中預設的函式可見性是什麼？**

如果程式碼中沒有明確宣告函式的可見性修飾符，該函式預設會設為 public 可見性。將函式可見性留空、依賴 Solidity 編譯器套用預設可見性，並非建議的最佳做法；明確設定函式可見性能讓程式碼在程式碼審查時更易讀、更容易理解。

## **函式與狀態變數可見性修飾符有什麼差異？**

**函式可見性修飾符與狀態變數可見性修飾符的差異在於，狀態變數沒有 external 可見性修飾符這個選項。**

狀態變數是其數值永久儲存在合約儲存空間（storage）中的變數，這些資料會在函式呼叫之間持續保存。與函式可見性修飾符相同，狀態變數也有可見性修飾符，分別是 Public、Private 與 Internal。

### **狀態變數可見性修飾符**

狀態變數是在程式的合約區段中宣告的。先指定變數的資料型別，接著再為該變數指定可見性修飾符。

#### **1. Public**

具有 _public_ 修飾符的狀態變數可以被應用程式中任何合約存取。如果變數被宣告為 _public_，其中儲存的資料可以被主合約、衍生合約或外部合約讀取。

#### **2. Internal**

使用 _internal_ 修飾符宣告的狀態變數，只能在定義它們的合約內部以及衍生合約中存取。第三方或其他外部合約無法存取被定義為 _internal_ 變數的資料儲存空間。

#### **3. Private**

如果狀態變數為 _private_，只有宣告它的主合約可以呼叫它。_private_ 可見性修飾符會限制主合約以外的其他各方存取，藉此保護其所持有的資料。

### **Solidity 中預設的變數可見性是什麼？**

當變數可見性未被定義時，預設值為 internal。最佳做法是將變數宣告為 private，直到需要擴大其存取範圍為止。

## **持續學習 Solidity**

本文為您介紹 Solidity 的函式可見性，並提供相關說明與資源，供您下一個專案使用。

如果您是 Solidity 語言的新手，並期待打造您的第一個智能合約，歡迎至 Alchemy University 免費的[線上 Solidity 程式設計課程](https://alchemy.com/university/courses/solidity?a=d7f2788ae5)搶先報名。
