什麼是 Yul?
Yul 是一種中間程式語言,可用來在智能合約中撰寫組合語言的形式。雖然我們常看到 Yul 用在智能合約內部,但你也可以完全用 Yul 撰寫一個智能合約。
理解 Yul 能提升你的智能合約撰寫能力,並讓你了解 solidity 底層的運作原理,進而幫助你節省使用者的 gas 成本。
我們可以透過以下語法在智能合約中辨識出 Yul。
在本文接下來的部分,我們將透過範例討論使用 Yul 的基礎知識,並建議你在 Remix 中一併操作。
Yul 中的變數賦值、運算與求值
我們首先要介紹的是簡單的運算。Yul 有 +、-、、/、%、、<、> 和 =。
請注意,>= 和 <= 並不在 Yul 可用運算子的清單中,因為 Yul 沒有這些運算子。此外,求值的結果不是 true 或 false,而是分別對應 1 或 0。話不多說,我們開始學習一些 Yul 吧!
在繼續之前,讓我們先快速看一個範例。
Yul 中的 for 迴圈與 if 陳述式
為了學習 for 迴圈和 if 陳述式,讓我們撰寫一個函式,計算一系列數字中有多少個偶數。
if 陳述式的語法與 Solidity 類似,但你不需要將條件放在括號中。
至於 for 迴圈,請注意我們在宣告 i 及遞增 i 時使用了大括號,但在評估條件時則沒有使用。此外,我們用了 continue 來跳過迴圈的某次迭代。在 Yul 中我們也可以使用 break 陳述式。
Yul 中儲存體(storage)的運作方式
一個智能合約有 2²⁵⁶ 個儲存槽(slot)。在宣告變數時,我們從第 0 個槽開始,依序遞增。每個槽長度為 256 位元(32 bytes);這也是 uint256 和 bytes32 名稱的由來。所有變數都會被轉換為十六進位。如果使用的是像 uint128 這樣的變數,我們不會用整個槽來儲存它,而是在左側以 0 填補。
想進一步了解 Yul 儲存體的運作方式,可以閱讀我們另一篇涵蓋以下主題的文章:
- 陣列(Arrays)
- 動態陣列(Dynamic arrays)
- 映射(Mappings)
- 巢狀映射(Nested Mappings)
如何在 Yul 中讀寫封裝變數(packed variables)
封裝變數(packing variables)指的是安排變數順序,使其儲存空間總和小於 32 bytes,讓它們能一起放入同一個槽中!封裝變數可以節省 gas,是智能合約優化的重要技巧。
舉例來說,0x000000000000000000000000000002 和 0x000000000000000000000000000001 剛好能完美地放入同一個槽,因為它們各佔 16 bytes(半個槽)。
想進一步了解如何在 Yul 中讀寫封裝儲存變數,歡迎閱讀我們的深入解析文章!
Yul 中的記憶體(memory)如何運作?
記憶體的行為與儲存體不同,因為它不具持久性(也就是說,一旦函式執行完畢,所有變數都會被清除)。Yul 中記憶體的一些用途包括:
- 回傳外部呼叫的值
- 設定外部呼叫的函式值
- 從外部呼叫取得值
- 以錯誤訊息字串進行 revert
- 記錄訊息(logging)
想進一步了解 Yul 記憶體的運作方式,歡迎閱讀我們另一篇深入探討此主題的文章!
Yul 中的合約呼叫如何運作?
當你了解了 Yul 的語法、儲存體以及記憶體的運作方式後,接下來就該學習呼叫合約了。我們 Yul 系列的最後一篇文章說明了合約在 Yul 中如何被呼叫,具體透過以下方式:
call()- 呼叫位於位址 a 的合約,出錯時回傳 0,成功時回傳 1staticcall()- 與 call(g, a, 0, in, insize, out, outsize) 相同,但不允許修改狀態delegatecall()- 與 callcode 相同,但同時保留 caller 與 callvalue
更多關於合約呼叫定義的資訊,可以在 Yul 語言文件中找到。
相關總覽

打造區塊鏈魔法
Alchemy 結合最強大的 Web3 開發者產品與工具,並提供資源、社群與卓越的支援。


