--- title: 'Solidity WTF 101 7 單元' lang: zh-tw --- Solidity WTF 101 7 單元 === :::info :date: 2024/09/25 ::: [TOC] ## 補充 ### uint問題 其他學員有提到 ``` 請問uint8 uint256的8位 256位數 是指十進制整數的8位,256位嗎? 還是2進制的8位跟256位呢? ``` 在提到之前也有這個疑問 但答案就是2進制。 * uint8 表示一個 8位元的無符號整數,意思是它可以表示的數值範圍是二進制 8 個位元 (bits)。它可以表示的範圍是從 0 到 2^8 - 1(即 0 到 255)。 * uint256 表示一個 256位元的無符號整數,它可以表示的範圍是從 0 到 2^256 - 1,這是一個非常大的範圍。 ## 課程學習 ### 映射關係 下面第一行代表一個型別為`uint`的數字,對應到一個`address`,白話就是如果我輸入`1`,那他就會返回`1`的`address`,因為他是映射關係,可以當成`1`是`key`,`address`是`value`,只要給予`key`就會返回`value`這就是映射,不只在`Solidity`很常使用,在其他語言上也會很常使用到`mapping`的概念。 ```xml= mapping(uint => address) public idToAddress; // id映射到地址 mapping(address => address) public swapPair; // 币对的映射,地址到地址 ``` ### 映射規則 :::info :information_source: 以下是從課程中直接複製過來,我認為很淺顯易懂,所以直接copy過來 ::: * 規則1 只能使用`Solidity`內規定的預設型別,不能使用自訂的`Struct` ```xml= <!-- 這是錯誤範例 --> struct Student{ uint256 id; uint256 score; } <!-- 無法使用自訂義結構當作key --> mapping(Student => uint) public testVar; ``` * 规则2:映射的存储位置必须是storage,因此可以用于合约的状态变量,函数中的storage变量和library函数的参数(见例子)。不能用于public函数的参数或返回结果中,因为mapping记录的是一种关系 (key - value pair)。 * 规则3:如果映射声明为public,那么Solidity会自动给你创建一个getter函数,可以通过Key来查询对应的Value。 * 规则4:给映射新增的键值对的语法如下 ```xml= function writeMap (uint _Key, address _Value) public{ idToAddress[_Key] = _Value; } ``` ### 映射原理 :::info :information_source: 以下是從課程中直接複製過來,我認為很淺顯易懂,所以直接copy過來 ::: * `原理1`: 映射不储存任何键(Key)的资讯,也没有`length`的资讯。 * `原理2`: 映射使用`keccak256(abi.encodePacked(key, slot))`当成`offset`存取`value`,其中slot是映射变量定义所在的插槽位置。 * `原理3`: 因为`Ethereum`会定义所有未使用的空间为0,所以未赋值(Value)的键(Key)初始值都是各个`type`的默认值,如`uint`的默认值是`0`。 ### 儲存機制 --- | 類型 | 永久存储(Storage) | 記憶體(Memory) | | -------- | -------- | -------- | | 存儲位置 | 區塊鏈上,永久保存 | 臨時存儲,只在函數調用期間存在 | | 變量類型 | 狀態變量(如 `uint`, `mapping`, `struct` 等) | 局部變量和函數參數 | | 存取成本 | 高`Gas Fee` | 低`Gas Fee` | | 數據持久性 | 持久化,交易結束後仍然存在 | 函數執行完畢後數據被釋放 | | 映射存儲位置 | 使用 `keccak256` 計算哈希值,將 `key` 和 `slot` 結合,存儲在鏈上 | 映射的值不會存儲在記憶體中 | ### 映射的存儲過程 --- 當你定義一個映射時,例如 `mapping(uint => uint) myMap;`,系統會將 `myMap` 分配一個存儲插槽(slot)。但實際的 `key-value` 並不是直接存儲在這個插槽中,而是通過以下方式計算出存儲地址: 1. 計算存儲位置: * `slot` 是映射變量的插槽位置,例如 `myMap` 在 `slot` = 1。 * `key` 是映射中存儲的具體鍵值。 * 存儲位置的計算公式為:`keccak256(abi.encodePacked(key, slot))`。 2. 存儲過程: * `Solidity` 使用 `keccak256` 將 `key` 和 `slot` 進行哈希計算,這個哈希結果用來作為映射中具體 `key-value` 對的存儲位置。 * 這些數據被存儲在區塊鏈的永久存儲區中。 ### 簡單流程圖描述: --- ```xml= myMap (slot 1) key = 123 | | slot 1 + key -> keccak256(123 + 1) -> 假設結果為位置 0xabc | 存儲 myMap[123] 對應的 value ``` ### 例子: --- 假設我們有一個智能合約: ```xml= contract MyContract { mapping(uint => uint) public myMap; // slot 1 } ``` 1. 映射變量 `myMap` 的插槽是 1。 2. 當你訪問 `myMap[123]` 時,會計算哈希 `keccak256(abi.encodePacked(123, 1))`,得到一個存儲地址,例如 `0xabc`。 3. `myMap[123]` 的值將存儲在這個位置 `0xabc`,並且這個值會永久存儲在鏈上,直到被更改。 ### 印射例子: ```javascript= // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract SimpleMappingExample { // 定義一個從地址到 uint 的映射 mapping(address => uint) public addressToAmount; // 設置某個地址對應的數值 function setAmount(uint _amount) public { // 詳細解釋就是addressToAmount這個map,他對應的key(address msg.sende 也就是操作此合約的address),value是_amount addressToAmount[msg.sender] = _amount; } // 查詢某個地址對應的數值 function getAmount(address _address) public view returns (uint) { // 你直接調用key會帶出value,與array[0]概念差不多 return addressToAmount[_address]; } } ```
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up