---
title: "Solidity 智能合約簡介"
description: "全面了解 Ethereum 智能合約"
---

# Solidity 智能合約簡介

Solidity 智能合約有多種用途，從多重簽章錢包到去中心化交易所都有。Solidity 是專為建立智能合約而生的主要 web3 程式語言之一，因此普及度持續上升。

本文將介紹 Solidity 智能合約、其運作方式與特性。我們也會帶你了解 Solidity 智能合約的語法與資料型別，讓你開始能夠與 Solidity 智能合約互動，運用在你的下一個專案中。若想進一步充實你的 Solidity 知識，可以完成 Alchemy University 的[免費 Solidity 語法課程](https://www.alchemy.com/university/courses/solidity)。

## **什麼是 Solidity 智能合約？**

Solidity 智能合約是一個[以 Solidity 撰寫](https://www.alchemy.com/overviews/solidity)、部署到 Ethereum 區塊鏈、並在 [Ethereum Virtual Machine](https://www.alchemy.com/overviews/what-is-the-ethereum-virtual-machine-evm)（EVM）中執行的程式。Ethereum 會將智能合約的程式碼與資料（其狀態）儲存在指定的位址上。

當預先設定的條件成立時，儲存在區塊鏈上的程式（即智能合約）便會執行，不需要中介者參與。換句話說，智能合約是控制 Ethereum 狀態內帳戶行為的程式。

你可以用 Solidity 或任何其他相容 EVM 的程式語言撰寫智能合約。這些程式必須先編譯成位元組碼（bytecode），才能與 EVM 相容。

Solidity 是一種物件導向、高階的智能合約撰寫語言。以 Solidity 撰寫的智能合約可用於各種用途，例如投票、群眾募資、盲拍以及多重簽章錢包。

## 智能合約如何運作？

智能合約是儲存在區塊鏈上的程式。智能合約以程式碼強化各方之間的協議，並在預設條件成立時自動執行規則。這代表智能合約涉及的所有各方能立即確定結果，不需耗費時間，也不需第三方介入。智能合約還能自動化工作流程，在執行後觸發下一個事件。

遵循 [ERC20 標準](https://www.alchemy.com/overviews/erc20-solidity)的智能合約被視為 ERC20 代幣。ERC20 代幣允許代幣持有者之間互相轉移代幣。

## **Solidity 智能合約有哪些特性？**

智能合約本質上是不可變且具確定性的。這代表一旦智能合約部署或建立在 Ethereum 上，除非其中已編寫觸發自毀（self-destruct）的條件，否則它將永遠存在。程式碼將永遠按其設定的條件執行。

此外，智能合約具有確定性，因為每個網路節點在給定相同輸入時，對同一個方法都能得出相同結果。若不同節點在執行智能合約時得出不同結果，便違反了共識協議，該智能合約也將無法使用。

智能合約也是[無需許可（permissionless）](https://www.alchemy.com/overviews/permissionless-vs-permissioned-blockchains)的，這代表任何擁有 ETH 且能連上網際網路的人，都能在 Ethereum 上部署智能合約。

最後，智能合約具有可組合性（composable）。這代表你可以將其他專案的智能合約當作組件，用於自己的專案中。智能合約可以被視為開放的 API，使用者不需要自行撰寫智能合約就能成為 dApp 開發者，只需要知道[如何與它們互動](https://docs.soliditylang.org/en/v0.8.13/abi-spec.html)即可。

## **Solidity 智能合約語法**

雖然坊間有許多資源可以幫助你[開始學習 Solidity](https://www.alchemy.com/overviews/learn-solidity)，本節將概述撰寫 Solidity 智能合約時所使用的語法。

### **1. 合約（Contracts）**

Solidity 中的合約類似於物件導向語言中的類別（class）。每個合約可以包含狀態變數（State Variables）、函式（Functions）、函式修飾器（Function Modifiers）、事件（Events）、錯誤（Errors）、結構型別（Struct Types）以及列舉型別（Enum Types）的宣告。本文將更詳細討論建構子（Constructors）、狀態變數與整數變數。此外，合約還可以繼承其他合約。

還有一種特殊的合約，稱為函式庫（library）與[介面（interface）](https://www.alchemy.com/overviews/solidity-interface)。

### **2. 語意化版本控制**

Solidity 和大多數軟體一樣，採用語意化版本控制（semantic versioning）。這代表除非更新的是主要版本號，否則不會有重大變更。你可以在文件上查看每個 Solidity 版本引入的主要重大變更。截至 2022 年 8 月，Solidity 最新的版本為 **v0.8.16**。

### **3. 建構子（Constructor）**

建構子只會在部署（即合約建立）時被呼叫一次。建構子是使用 constructor 關鍵字宣告的[選用函式](https://www.alchemy.com/overviews/solidity-functions)，讓你能夠執行合約的初始化程式碼。

在建構子程式碼執行之前，狀態變數會先被初始化：若你以行內方式初始化，則設為指定值；若沒有，則設為預設值。

建構子執行完畢後，合約最終的程式碼便會部署到區塊鏈上。

如果沒有建構子，合約會採用預設建構子。

### **4. 狀態變數**

狀態變數是其值儲存在合約儲存空間（storage）中的變數。每個函式都有自己的作用域，而狀態變數應該永遠定義在該作用域之外。

狀態變數遵循可見性（visibility）規則。你可以使用 [_public_ 可見性關鍵字](https://www.alchemy.com/overviews/solidity-function-visibility)將狀態變數設為公開，這會提供一個 getter 函式，讓其他智能合約可以存取。

### **5. 修飾（Modification）**

在 Solidity 中，[修飾器（modifier）以宣告方式修改函式的語意](https://www.alchemy.com/overviews/solidity-modifier)。換句話說，修飾器會改變其所附加函式的行為。修飾器有助於消除程式碼冗餘，並可在智能合約中的多個函式中重複使用，用於檢查相同的條件。

### **6. 整數變數**

Solidity 中有兩種整數變數：[無號整數（uint）](https://www.alchemy.com/overviews/solidity-uint)與有號整數（int）。有號整數是一種可以儲存正值與負值的值型別。而無號整數則沒有符號，因此是一種必須為非負值的值型別。

## **Solidity 資料型別**

如同其他程式語言，Solidity 有多種資料型別分類。然而，Solidity 的獨特之處在於，多種基本資料型別可以組合成更複雜的資料型別。本節將概述 Solidity 中的主要資料型別。

### **1. 布林值（Booleans）**

布林值在 Solidity 中以 _bool_ 表示，其可能的值為常數 true 與 false。

### **2. 字串（Strings）**

字串字面值可以用雙引號或單引號撰寫。字串也可以拆分成多個連續的部分，這在處理長字串時會很有幫助。

### **3. 數字（Numbers）**

_Fixed_ 與 _ufixed_ 分別代表各種大小的有號與無號定點數（fixed point numbers）。

### **4. 位元組（Bytes）**

在 Solidity 中，byte 指的是 8 位元的有號整數。位元（bit）以二進位值 0 或 1 的形式儲存在記憶體中。在 Solidity 中，資料型別 byte 代表一連串的位元組。

Solidity 中有兩種位元組型別：**固定大小位元組陣列（fixed-sized byte arrays）**與**動態大小位元組陣列（dynamically-sized byte arrays）**。關鍵字 bytesX 用於定義變數，其中 X 代表位元組序列的長度，範圍從 1 到 32。

Solidity 中的 bytes 代表一個動態的位元組陣列。然而，它並非值型別（value type）。

### **5. 位址（Address）**

address 儲存 20 位元組的值，這也是 Ethereum 位址的大小。通過位址檢查碼（checksum）測試的十六進位字面值屬於 address 型別。長度介於 39 到 41 位數之間、但未通過檢查碼測試的十六進位字面值會產生錯誤。你可以在整數型別前補零，或在 bytesNN 型別後補零，以消除該錯誤。

### **6. 可支付位址（Payable address）**

[可支付位址（payable address）](https://www.alchemy.com/docs/solidity-payable-functions)，以 address payable 表示，與 address 類似，但額外具有 transfer 與 send 成員。這樣的區分是必要的，因為一般的 address 可能是未設計成接收 Ether（ETH）的智能合約。address payable 則是可以向其發送 Ether 的位址。

### **7. 列舉（Enums）**

列舉（Enums），在 Solidity 中也稱為 enumeration values，是建立使用者自定義型別的一種方式，可用來建立常數值，例如整數常數的名稱。相較於基本值型別，列舉能讓智能合約更容易閱讀與維護。

列舉可以顯式地與所有整數型別互相轉換，但不允許隱式轉換。從整數進行顯式轉換時，會在執行期檢查該值是否落在該列舉的範圍內，否則會導致 panic 錯誤。因此，列舉能降低程式碼中出現錯誤的機率。

列舉至少需要一個成員，宣告時的預設值為第一個成員。列舉最多不能超過 256 個成員。

### **8. 陣列（Arrays）**

陣列是[一組相同資料型別的變數](https://www.alchemy.com/overviews/solidity-arrays)，每個變數都有唯一的索引。陣列可以在編譯期就有固定大小，此時稱為**固定陣列（fixed arrays）**；也可以有動態大小，此時稱為**動態陣列（dynamic arrays）**。

固定大小陣列在宣告時就有預先定義的大小。不能使用 new 關鍵字來新增額外的陣列成員，必須以行內方式初始化資料變數。

動態大小陣列在宣告時沒有預先定義的大小，其大小是在執行期決定的。

陣列元素可以是任何型別，包括 mapping 或 struct（一種使用者自定義的資料結構）。

### **9. 映射（Mappings）**

在 Solidity 中，[mapping 的運作方式類似於雜湊表（hash table）](https://www.alchemy.com/overviews/solidity-mapping)，或其他程式語言中的字典（dictionary）。mapping 作為一種參考型別（reference type），以鍵值對的形式儲存資料，其中鍵可以是除了參考型別以外的任何內建資料型別，而值則可以是任何型別。

如果一個 mapping 型別的狀態變數是 public 的，Solidity 會自動為你建立一個 getter 函式。

### **10. 結構（Structs，使用者自定義型別）**

struct（結構）讓你能夠[定義新的資料型別](https://www.alchemy.com/overviews/solidity-struct)。struct 型別可以用在 mapping 與陣列內部，並且它們本身也可以包含巢狀的 mapping 與陣列。然而，struct 不能包含其自身型別的成員，因為 struct 的大小必須是有限的。

## **什麼是智能合約情境（context）？**

**智能合約情境提供關於交易所在執行環境的資訊。** 當智能合約函式透過交易被呼叫時，被呼叫的函式會收到一些額外傳入的資訊。在智能合約函式內，你可以存取這些情境變數。

你可以存取訊息發送者（message sender）、gas 價格，以及該交易所執行的測試。因此，你可以在程式碼邏輯中交替使用一系列的情境變數。

## **報名 Ethereum 開發者訓練營以進一步學習**

在本文中，我們介紹了 Solidity 智能合約入門的基礎知識，並概述了關鍵的資料型別與語法，以增進你的理解。報名 Alchemy 的[免費線上 Ethereum Developer Bootcamp](https://www.alchemy.com/university/courses/ethereum)，以進一步學習如何使用 Solidity 建立智能合約。如果開發者對開發完全是新手，Alchemy University 的[三週 JavaScript for Ethereum 速成課程](https://www.alchemy.com/university/courses/js)會是很好的先修課程。
