---
title: "如何在 Yul 中讀取與寫入 packed storage 變數"
description: "了解如何在 Yul 中讀取與寫入 packed storage 變數"
---

# 如何在 Yul 中讀取與寫入 packed storage 變數

[Yul](http://www.alchemy.com/overviews/what-is-yul) 是一種中介程式語言，可以用來在[智能合約](https://www.alchemy.com/overviews/solidity-smart-contract)內撰寫組合語言。在了解 Yul 的語法以及 storage 的運作方式後，接下來要學的是如何在 Yul 中讀寫 packed storage 變數。

## **如何在 yul 中讀寫 packed storage 變數**

假設你想把 var5 改成 4。我們知道 var5 位於 slot 3，所以你可能會試著這樣寫：

用 getValInHex\(3\) 查看，會發現 slot 3 被改寫成：

`0x0000000000000000000000000000000000000000000000000000000000000004`

這就有問題了，因為現在 var4 也被改寫成 0 了。這一節我們要說明如何讀寫 packed 變數，但在那之前得先多了解一些 Yul 的語法。

如果你不熟悉這些運算子也沒關係，我們會用範例一一說明。

先從 and\(\) 開始。我們拿兩個 bytes32，試試 and\(\) 運算子，看看會回傳什麼。

看輸出結果會發現：

`0x0000000000000000000000009acc1d6aa9b846083e8a497a661853aae07f0f00` 

原因在於 and\(\) 是逐一比對兩個輸入中每一個 bit 的值。

如果兩個 bit 都是 1（用二進位的角度來想：啟用或未啟用），那個 bit 就會保持原樣。

否則就會被設成 0。

接著看看 or\(\) 的程式碼。

這次的輸出是：

`0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`

這是因為 or\(\) 檢查的是「兩者之一」的 bit 是否啟用。

再來看看如果把 mask 變數改成：

`0x00ffffffffffffffffffffff0000000000000000000000000000000000000000`

會發生什麼事。

如你所見，輸出變成了：

`0x00ffffffffffffffffffffff9acc1d6aa9b846083e8a497a661853aae07f0f00`

注意第一個 byte 是 0x00，因為兩個輸入在第一個 byte 都沒有任何啟用的 bit。

xor\(\) 稍微不一樣。它要求其中一個 bit 是啟用（1），另一個 bit 是未啟用（0）。

**以下是程式碼示範：**

輸出是：

`0xffffffffffffffffffffffff0000000000000000000000000000000000000000`

主要的差異在於，輸出中只有在 0x00 和 0xff 對齊的位置才會出現啟用的 bit。

shl\(\) 和 shr\(\) 的運作方式非常相似。兩者都會把輸入值移動指定的 bit 數。shl\(\) 是往左移，shr\(\) 是往右移。

來看一些程式碼吧！

輸出：

ans1: `0x0000ffff00000000000000000000000000000000000000000000000000000000`

ans2: `0x00000000000000000000000000000000000000000000000000000000ffff0000`

先來看 ans1。我們對它做了 16 bit（2 byte）的 shr\(\)。可以看到最後兩個 byte 從 0xffff 變成 0x0000，而前兩個 byte 則往右移了兩個 byte。了解這點之後，ans2 就很好理解了；差別只在於這次是往左移而不是往右移。

**在寫入 var5 之前，我們先寫一個函式，讀取 var4 和 var5。**

輸出結果如預期，分別是 1 和 2。

要取得 var4，我們只需用 mask 把值設成：

`0x0000000000000000000000000000000000000000000000000000000000000001`

然後回傳一個等於 1 的 uint128。

讀取 var5 時，我們需要把 var4 的部分移除，方法是往右移。

這樣就會得到以下結果，可以直接回傳：

`0x0000000000000000000000000000000000000000000000000000000000000002`

要注意的是，如果一個 storage slot 裡塞了超過兩個變數，有時候需要同時做 shift 和 mask 才能讀到正確的值。

**好，現在終於可以把 var5 的值改成 4 了！**

第一步是載入 storage slot 3。

接著，我們要建立一個 mask。

跟讀取 var4 時類似，我們要把值隔離成：

`0x0000000000000000000000000000000000000000000000000000000000000001`

下一步是把新值格式化到 var5 在該 slot 中的位置，變成這樣：

`0x0000000000000000000000000000000400000000000000000000000000000000`

跟讀取 var5 時不同，這次我們要把值往左移。

最後，我們用 or\(\) 把這些值合併成 32 個 byte 的十六進位值，並把該值存入 slot 3。

我們可以呼叫 getValInHex\(3\) 來檢查結果。

回傳的會是這個，，正是我們預期的結果：

`0x0000000000000000000000000000000400000000000000000000000000000001`

太好了，你現在已經知道如何讀寫 packed storage slot 了！接下來，了解 Yul 中 [Memory](http://www.alchemy.com/overviews/yul-memory)、[Storage](http://www.alchemy.com/overviews/yul-storage) 以及 [Smart Contract Calls](http://www.alchemy.com/overviews/yul-contract-calls) 的運作方式。
