---
title: "什麼是 Yul？"
description: "了解如何用 Yul 撰寫智能合約，以及它與 Solidity 的差異"
---

# 什麼是 Yul？

Yul 是一種中間[程式語言](https://www.alchemy.com/overviews/web3-programming-languages)，可用來在[智能合約](https://www.alchemy.com/overviews/solidity-smart-contract)中撰寫組合語言的形式。雖然我們常看到 Yul 用在智能合約內部，但你也可以完全用 Yul 撰寫一個智能合約。

理解 Yul 能提升你的智能合約撰寫能力，並讓你了解 [solidity](https://www.alchemy.com/overviews/solidity) 底層的運作原理，進而幫助你節省使用者的 gas 成本。

我們可以透過以下語法在智能合約中辨識出 Yul。

在本文接下來的部分，我們將透過範例討論使用 Yul 的基礎知識，並建議你在 Remix 中一併操作。

## **Yul 中的變數賦值、運算與求值**

我們首先要介紹的是簡單的運算。Yul 有 \+、-、、/、%、、&lt;、&gt; 和 =。

請注意，&gt;= 和 &lt;= 並不在 Yul 可用運算子的清單中，因為 Yul 沒有這些運算子。此外，求值的結果不是 true 或 false，而是分別對應 1 或 0。話不多說，我們開始學習一些 Yul 吧！

<EmbeddedTable
  table={{
    columns: [
      { key: "1", width: 200, title: "Instruction", dataType: "object" },
      { key: "2", width: 200, title: "Explanation", dataType: "object" },
    ],
    data: [
      {
        "1": { title: "<p>let</p>", tooltip: "", icon: "" },
        "2": { title: "<p>This is required before defining a variable. Since all values are bytes, there is no need to assign a value type.</p>", tooltip: "", icon: "" },
        id: 0,
      },
      {
        "1": { title: "<p>:=</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Solidity equivalent: x = y</p>", tooltip: "", icon: "" },
        id: 1,
      },
      {
        "1": { title: "<p>add(x,y)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Solidity equivalent: x + y</p>", tooltip: "", icon: "" },
        id: 2,
      },
      {
        "1": { title: "<p>sub(x,y)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Solidity equivalent: x - y</p>", tooltip: "", icon: "" },
        id: 3,
      },
      {
        "1": { title: "<p>mul(x,y)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Solidity equivalent: x * y</p>", tooltip: "", icon: "" },
        id: 4,
      },
      {
        "1": { title: "<p>div(x,y)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Solidity equivalent: x / y (or 0 if y equals 0)</p>", tooltip: "", icon: "" },
        id: 5,
      },
      {
        "1": { title: "<p>mod(x,y)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Solidity equivalent: x % y (or 0 if y equals 0)</p>", tooltip: "", icon: "" },
        id: 6,
      },
      {
        "1": { title: "<p>lt(x,y)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Solidity equivalent: x < y</p>", tooltip: "", icon: "" },
        id: 7,
      },
      {
        "1": { title: "<p>gt(x,y)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Solidity equivalent: x > y</p>", tooltip: "", icon: "" },
        id: 8,
      },
      {
        "1": { title: "<p>eq(x,y)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Solidity equivalent: x == y</p>", tooltip: "", icon: "" },
        id: 9,
      },
      {
        "1": { title: "<p>iszero(x)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Solidity equivalent: x == 0</p>", tooltip: "", icon: "" },
        id: 10,
      },
    ],
  }}
/>

在繼續之前，讓我們先快速看一個範例。

## **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 儲存體的運作方式](http://www.alchemy.com/overviews/yul-storage)，可以閱讀我們另一篇涵蓋以下主題的文章：

1. 陣列（Arrays）
1. 動態陣列（Dynamic arrays）
1. 映射（Mappings）
1. 巢狀映射（Nested Mappings）

## **如何在 Yul 中讀寫封裝變數（packed variables）**

封裝變數（packing variables）指的是安排變數順序，使其儲存空間總和小於 32 bytes，讓它們能一起放入同一個槽中！封裝變數可以節省 gas，是智能合約優化的重要技巧。

舉例來說，`0x000000000000000000000000000002` 和 `0x000000000000000000000000000001` 剛好能完美地放入同一個槽，因為它們各佔 16 bytes（半個槽）。

想進一步了解[如何在 Yul 中讀寫封裝儲存變數](http://www.alchemy.com/overviews/yul-packed-storage-variables)，歡迎閱讀我們的深入解析文章！

## **Yul 中的記憶體（memory）如何運作？**

記憶體的行為與儲存體不同，因為它不具持久性（也就是說，一旦函式執行完畢，所有變數都會被清除）。Yul 中記憶體的一些用途包括：

1. 回傳外部呼叫的值
1. 設定外部呼叫的函式值
1. 從外部呼叫取得值
1. 以錯誤訊息字串進行 revert
1. 記錄訊息（logging）

想進一步了解 [Yul 記憶體的運作方式](http://www.alchemy.com/overviews/yul-memory)，歡迎閱讀我們另一篇深入探討此主題的文章！

## **Yul 中的合約呼叫如何運作？**

當你了解了 Yul 的語法、儲存體以及記憶體的運作方式後，接下來就該學習呼叫合約了。我們 Yul 系列的最後一篇文章說明了[合約在 Yul 中如何被呼叫](http://www.alchemy.com/overviews/yul-contract-calls)，具體透過以下方式：

1. `call()` - 呼叫位於位址 a 的合約，出錯時回傳 0，成功時回傳 1
1. `staticcall()` - 與 call\(g, a, 0, in, insize, out, outsize\) 相同，但不允許修改狀態
1. `delegatecall()` - 與 callcode 相同，但同時保留 caller 與 callvalue‍

更多關於合約呼叫定義的資訊，可以在 [Yul 語言文件](https://docs.soliditylang.org/en/v0.8.19/yul.html#yul-call-return-area)中找到。
