本節是《Solidity by Example》的中文翻譯與深入講解,專為零基礎或剛接觸區塊鏈開發的小白朋友打造。我們將通過“示例 + 解說 + 提示”的方式,帶你逐步理解每一段 Solidity 代碼的實際用途與背后的邏輯。
Solidity 是以太坊等智能合約平臺使用的主要編程語言,就像寫網頁要用 HTML 和 JavaScript,寫智能合約就需要會 Solidity。
如果你從沒寫過區塊鏈代碼也沒關系,只要你了解一點點編程概念,比如“變量”“函數”“條件判斷”,我們就能從最簡單的例子開始,一步步建立你的 Solidity 編程思維。
Reading and Writing to a State Variable
讀寫狀態變量
要寫入或更新狀態變量,你需要發送一筆交易。 另一方面,你可以免費讀取狀態變量,無需支付交易費用
- 狀態變量:狀態變量是存儲在區塊鏈上的數據(例如一個數字或字符串),它們是智能合約的“持久化”數據,類似于數據庫中的記錄。
- 寫入狀態變量:
- 修改狀態變量(例如更新一個數字)需要發送一筆交易(transaction)。
- 交易會改變區塊鏈的狀態,因此需要支付 Gas 費用(以太坊的計算和存儲費用)。
- 交易必須由用戶或另一個合約發起,并由區塊鏈網絡確認。
- 讀取狀態變量:
- 讀取狀態變量(例如查看當前值)不需要發送交易。
- 如果通過 鏈下調用(off-chain call,例如通過 Web3 庫查詢),讀取是免費的,因為它不會改變區塊鏈狀態。
- 通常,讀取函數會標記為
view
,表示它們只讀數據,不消耗 Gas。
// SPDX-License-Identifier: MIT
// 聲明代碼采用 MIT 開源許可證,這是一種常見的開源許可協議,允許自由使用、修改和分發代碼。pragma solidity ^0.8.26;
// 指定 Solidity 編譯器版本必須大于或等于 0.8.26 并且小于 0.9.0。
// `pragma` 指令確保合約使用兼容的編譯器版本,`^0.8.26` 表示支持 0.8.26 或更高版本(但不超過 0.9.0)。contract SimpleStorage {// 定義一個名為 `SimpleStorage` 的智能合約。// 合約是一個運行在以太坊區塊鏈上的程序,包含數據(狀態變量)和邏輯(函數)。// 這個合約的目的是展示如何讀寫狀態變量。// State variable to store a number// 用于存儲數字的狀態變量uint256 public num;// 聲明一個名為 `num` 的狀態變量,類型為 `uint256`(256 位無符號整數,范圍從 0 到 2^256-1)。// `public` 關鍵字表示該變量可以被外部訪問,Solidity 會自動為其生成一個 getter 函數(類似于 `function num() public view returns (uint256)`)。// 未初始化,默認值為 0,存儲在區塊鏈上。// You need to send a transaction to write to a state variable.// 你需要發送一筆交易來寫入狀態變量。function set(uint256 _num) public {// 定義一個名為 `set` 的公共函數,用于更新狀態變量 `num`。// 接受一個參數 `_num`,類型為 `uint256`,表示要設置的新值。// `public` 表示函數可以被外部調用(用戶、其他合約或 DApp)。// 沒有 `view` 或 `pure` 修飾符,表示函數會修改區塊鏈狀態,需要消耗 Gas。num = _num;// 將狀態變量 `num` 的值更新為傳入的參數 `_num`。// 修改狀態變量會觸發區塊鏈存儲更新,因此需要發送交易并支付 Gas。}// You can read from a state variable without sending a transaction.// 你可以無需發送交易即可讀取狀態變量。function get() public view returns (uint256) {// 定義一個名為 `get` 的公共函數,用于讀取狀態變量 `num` 的值。// `public` 表示函數可以被外部調用。// `view` 修飾符表示函數只讀取區塊鏈數據,不修改任何狀態,因此鏈下調用免費。// 返回值類型為 `uint256`,表示返回 `num` 的當前值。return num;// 返回狀態變量 `num` 的當前值。}
}
SimpleStorage
是一個簡單的智能合約,展示了如何在以太坊區塊鏈上讀寫狀態變量。它包含:
- 一個狀態變量
num
,用于存儲一個數字(初始值為 0)。 - 一個函數
set
,用于更新num
的值(寫入操作)。 - 一個函數
get
,用于查看num
的當前值(讀取操作)。
代碼做什么?
- 狀態變量
num
:- 存儲一個數字,永久保存在區塊鏈上。
- 因為是
public
,可以直接通過 getter 函數(num()
)或get
函數讀取。
- 寫入操作(
set
函數):- 接受一個新數字
_num
,更新num
的值。 - 修改區塊鏈上的數據需要發送交易,消耗 Gas。
- 例如,調用
set(42)
會將num
改為 42。
- 接受一個新數字
- 讀取操作(
get
函數):- 返回
num
的當前值。 - 只讀取數據,不修改區塊鏈狀態,因此鏈下調用免費。
- 例如,調用
get()
會返回當前的num
值(如 42)。
- 返回
- Gas 成本:
- 部署合約時,初始化
num
(默認 0)需要 Gas。 - 調用
set
函數修改num
需要 Gas(因為更改區塊鏈狀態)。 - 調用
get
函數或num
的 getter 函數是view
操作,鏈下調用不消耗 Gas。
- 部署合約時,初始化
關鍵點:
- 狀態變量:
- 存儲在區塊鏈的
storage
中,永久保存。 - 修改需要交易和 Gas,讀取通常免費。
- 存儲在區塊鏈的
- 交易 vs. 調用:
- 交易(Transaction):修改區塊鏈狀態(如調用
set
),需要 Gas,記錄在區塊鏈上。 - 調用(Call):只讀取數據(如調用
get
),鏈下免費,不記錄在區塊鏈上。
- 交易(Transaction):修改區塊鏈狀態(如調用
- 公共變量:
public
變量自動生成 getter 函數,功能與get
函數類似。- 例如,
num
本身可以直接查詢,等價于調用get
。
- 用途:
- 讀寫狀態變量是智能合約的核心功能,廣泛用于存儲用戶數據、記錄狀態或實現業務邏輯。
- 例如,
SimpleStorage
可以用來記錄一個計數器、用戶余額或其他持久化數據。
讀寫狀態變量的注意事項
- 寫入需要交易:
- 任何修改狀態變量的操作(如
set
)都需要發送交易,消耗 Gas。 - 交易失敗(例如 Gas 不足或邏輯錯誤)會導致狀態回滾,但已消耗的 Gas 不退還。
- 任何修改狀態變量的操作(如
- 讀取免費:
view
函數(如get
)或public
變量的 getter 函數在鏈下調用免費。- 如果在鏈上調用(例如另一個合約調用
get
),會消耗少量 Gas。
- 狀態變量的存儲成本:
- 狀態變量存儲在區塊鏈的
storage
中,占用空間較大,初始化和修改成本高。 - 選擇合適的類型(如
uint8
比uint256
更省空間)可以優化 Gas。
- 狀態變量存儲在區塊鏈的
- 安全性:
public
變量可以被任何人讀取,注意不要存儲敏感數據。- 修改狀態變量時,考慮添加權限控制(例如只有管理員可以調用
set
)。
- 溢出檢查:
- 在 Solidity 0.8.0+ 中,
uint256
的算術運算自動檢查溢出/下溢,失敗時交易會回滾。
- 在 Solidity 0.8.0+ 中,