---
title: "Solidity 中的 mapping 是什麼？"
description: "了解 Solidity 中 mapping 的運作方式"
---

# Solidity 中的 mapping 是什麼？

[Solidity](https://www.alchemy.com/overviews/solidity) 中的 Mapping（映射）是一種雜湊表（hash table），以鍵值對（key-value pairs）的形式儲存資料，其中 key 可以是 Ethereum 支援的任何內建資料型別。Mapping 是[學習 Solidity 開發](https://www.alchemy.com/overviews/learn-solidity)時必須理解的基本概念。

本文說明什麼是 mapping、mapping 如何運作、mapping 與 array 之間的差異，並提供 mapping 的範例，幫助你在 Ethereum 及與 Solidity 相容的區塊鏈（如 Optimism 和 Arbitrum）上開發出最好的智能合約。

## **什麼是雜湊表（hash table）？**

雜湊表是一種以關聯方式儲存資料的資料結構。在雜湊表中，資料以 array 的形式保存，每個資料值都有自己獨一無二的索引值。雜湊表使用 array 作為儲存媒介，並採用雜湊技術來建立索引，藉此決定元素要插入或查找的位置。

<ImageBlock
  src="https://media.alchemy.com/1703922693-mapping-in-solidity.png"
  alt="Mappings in Solidity Explained by Doug Crescenzi"
  width={429}
  height={329}
  caption="來源：Mappings in Solidity Explained by Doug Crescenzi"
/>

當已知所需資料的索引時，可以極快地取得該資料。因此，無論資料量多寡，雜湊表都是插入與搜尋操作極為快速的資料結構。

## **Solidity 中的 mapping 是什麼？**

Mapping 是 Solidity 中的一種雜湊表，以鍵值對的形式儲存資料，其中 key 可以是任何內建資料型別（reference type 除外），value 的資料型別則可以是任意型別。

在 Solidity 和 Ethereum 區塊鏈中，mapping 最常見的用途是將一個獨一無二的 Ethereum address 對應到相應的 value 型別。

在其他程式語言中，mapping 相當於 dictionary（字典）。

### 雜湊表與 Solidity mapping 有什麼差異？

Mapping 的運作方式如同雜湊表，具有 key 型別與相對應 value 型別的配對，而 mapping 之所以有價值，是因為它能容納大量的 **\_KeyType** 對應到 **\_ValueType**。Mapping 沒有 length，也沒有「設定」某個 key 或 value 的概念。Mapping 僅適用於作為儲存 reference type 的 state variable。當 mapping 初始化時，會包含所有可能的 key，並對應到位元組表示全為零的 value。

Solidity 中定義 mapping 的方式與定義其他變數型別相同：

### Solidity 的 array 與 mapping 有什麼差異？

相較於 mapping，[**Solidity 的 array**](https://www.alchemy.com/overviews/solidity-arrays) 更適合用來迭代一組資料（例如使用 for 迴圈）；而當你能透過已知的 key 取得對應的 value（也就是不需要遍歷資料）時，mapping 則更為適合。

由於在 Solidity 中迭代 array 的成本可能比從 mapping 取得資料來得高，而開發者有時會希望在智能合約中同時儲存 value 及其 key，因此開發者有時會建立一個由 key 組成的 array，作為指向資料的參考，之後再從 mapping 中取得該資料。

開發者不應讓 Solidity 中的 array 變得過大，因為迭代大型 array 所耗費的 gas 費用可能超過交易本身的價值，這使得 mapping 成為[更省 gas 的智能合約實作方式](https://www.alchemy.com/overviews/solidity-gas-optimization)。

**以下是關於 mapping 的其他特性：**

- Mapping 沒有 length。
- Mapping 也沒有「設定」key 或 value 的概念。
- Mapping 只能用於作為儲存 reference type 的 state variable。

## **什麼是 nested mapping（巢狀映射）？**

Nested mapping 是指從一個 mapping 對應到另一個 mapping。舉例來說，如果我們有 username 和 age，並希望藉由一個特殊的 ID 來儲存這些資訊，讓其他人只能透過該 ID 取得這些資料，這在 Solidity 中稱為 double mapping。

以下是一個 nested mapping 的範例：

在這份合約中，我們建立了一個 nested mapping，稱為 User。在這個 mapping 中，我們串接了兩個 mapping：

1. 一個用來記錄特定使用者 id 的資訊
1. 一個用來儲存特定使用者的 name 與 age

以下的程式碼區塊是一個簡單的 getter function，用來回傳該使用者的資訊。

## **如何在 Solidity 中使用 mapping**

以下是在 Solidity 中使用 mapping 的範例。以下程式碼片段的功能包括：

- 從 address 映射到 uint，並確保 mapping 一定會回傳一個值
- 若該值從未被設定，則會回傳預設值
- 更新對應 address 的值
- 將該值重設為預設值
- 建立一個從 address 對應到另一個 mapping 的 nested mapping
- 即使 nested mapping 尚未初始化，也能從中取得值

## **Solidity mapping 範例**

以下是三個 Solidity mapping 的範例：

1. ERC20 token 餘額
1. 使用布林邏輯（boolean logic）
1. 查詢 DAO 成員

### **1. ERC20 使用者餘額**

這段程式碼將使用者的 address 對應到其 ERC20 餘額。

### **2. Solidity mapping bool 範例**

這段程式碼的設計目的是在清單中列出候選人的名字，並回傳該候選人獲得的票數。這個範例可應用於 [DAO](https://www.alchemy.com/dapps/top/daos)，成員需要對組織的決策進行投票。

### **3. 是否為成員（DAO）**

此範例來自 Dominion DAO 智能合約，其中對應了 _raisedProposals_、_stakeholderVotes_、_votedOn_、_contributors_ 以及 _stakeholders_。

這段程式碼範例列出了兩個 [Solidity struct](https://www.alchemy.com/overviews/solidity-struct)：_ProposalStruct_ 與 _VotedStruct_ 的欄位。

## **string 的 Solidity mapping**

為了更清楚理解，讓我們在建構 mapping 的過程中加入一些值。在以下範例中，我們會：

- 建立一份合約
- 定義一個 structure
- 宣告不同的 structure 元素
- 建立一個 mapping
- 為該 mapping 加入值

## **Solidity mapping 常見問題**

以下是關於 Solidity mapping 的一些常見問題：

1. Solidity mapping 的 length 是什麼？
1. Solidity mapping 的預設值是什麼？
1. 如何公開查看 Solidity mapping？

### **Solidity mapping 的 length 是什麼？**

**Mapping 沒有 length。key 的資料本身並不會儲存在 mapping 中，而是使用其 keccak256 雜湊值**來儲存該 key 所對應的 value。因此並不存在「單獨」的 key 或 value 的概念。

### **Solidity mapping 的預設值型別為何？**

以下是 Solidity mapping 的預設值型別：

- **int/uint** - key type = 是；value type = 是
- **string** - key type = 是；value type = 是
- **byte/bytes** - key type = 是；value type = 是
- **address** - key type = 是；value type = 是
- **struct** - key type = 否；value type = 是
- **mapping** - key type = 否；value type = 是
- **enum** - key type = 否；value type = 是
- **contract** - key type = 否；value type = 是
- **fixed-sized array** - key type = 是；value type = 是
- **dynamic-sized array** - key type = 否；value type = 是
- **multi-dimensional array** - key type = 否；value type = 是
- **variable** - key type = 否；value type = 否

### **如何公開查看 Solidity mapping？**

由於[該 property 是 public 的](https://www.alchemy.com/overviews/solidity-function-visibility)，你可以使用 **Solidity compiler** 所產生的 getter function 來存取它。
