Solidity 基础(第1部分)——变量、函数与你的第一个真实合约
Source: Dev.to
第26天 – 第三阶段:开发
60天Web3之旅 – Solidity基础
在60天Web3之旅短暂的两天暂停后,是时候重新启动,开启下一阶段,踏出我们的第一步——Solidity。
在过去的25天里,我们把智能合约当作神秘的自动售货机:你发起一次交易,链上就会发生某些事情。今天我们终于揭开盖子,开始阅读这些自动售货机所使用的语言:Solidity。
今日内容
- 了解基本构件——变量和函数。
- 将一个小而真实的合约部署到 Sepolia:Web3 Journey Logger。
目标: 并非要成为 Solidity 专家,而是掌握让你在链上存储和操作数据的基础。
1️⃣ Solidity 概览
Solidity 是一种高级、面向合约的编程语言,用于编写在以太坊及其他兼容 EVM 的链(Arbitrum、Optimism、Polygon,……)上运行的智能合约。
- 编译后 → 生成字节码,部署在链上特定地址。
- 执行 由处理你交易的每个节点完成。
如果你熟悉 JavaScript、C++ 或 TypeScript,Solidity 看起来会很熟悉:大括号、函数、变量、if 条件等。
两个关键区别:
- 你编写的是 金钱和状态,而不仅仅是 UI。
- 每一次操作都要消耗 gas,且你部署的代码大多是 永久 的。
Source: …
2️⃣ 变量 – 合约的内存
把智能合约想象成一个拥有自己私有数据库的链上小应用。变量就是合约存储数据的命名盒子。
在 Solidity 中,你必须始终声明变量的类型和名称,因为编译器需要确切知道要把什么存在哪里。
三种层级的变量
| 级别 | 作用域 | 持久性 | 典型用法 |
|---|---|---|---|
| 状态变量 | 永久存储在区块链上的合约存储中。 | 在函数调用和交易之间保持。 | 所有者地址、代币余额映射、计数器。 |
| 局部变量 | 在函数内部声明。 | 仅在该函数运行期间存在,随后消失。 | uint256 sum = a + b; 在函数内部使用。 |
| 全局变量 | 由 EVM 提供的内置助手。 | 在执行期间只能读取。 | msg.sender、block.timestamp、block.number。 |
在这一步我们重点关注 状态变量,因为它们构成了合约的链上内存。
核心数据类型(几乎每个合约都会用到的)
| 类型 | 描述 | 示例 |
|---|---|---|
bool | 存储 true 或 false。 | bool public completed; |
uint256 | 无符号整数(0 及正数)。常用于金额、ID、计数器、时间戳。 | uint256 public dayNumber; |
address | 存储以太坊地址(用户或合约)。 | address public owner; |
string | 存储文本数据。相较于数字消耗更多 gas,只有在需要时才使用。 | string public note; |
还有很多其他类型(
int、bytes、mapping、struct、数组等),但这四种足以让你入门。
3️⃣ 函数 – 门与按钮
如果变量是合约的内存,函数就是用户可以按下的门和按钮,用来读取或更新这些内存。
每当有人通过交易或用户界面(例如 dApp)调用函数时,EVM 会一步一步执行该函数的逻辑。
基本函数语法
function setDay(uint256 _day) public {
dayNumber = _day;
}
setDay– 函数名。uint256 _day– 输入参数。public– 可见性说明符。- 函数体(
{ … })更新dayNumber状态变量。
可见性修饰符
| Modifier | 谁可以调用? |
|---|---|
public | 任何人,包括其他合约。自动成为合约的外部接口。 |
external | 旨在 从合约外部 调用。对纯外部调用来说稍微更省 gas。 |
internal / private | 用于辅助函数;此处不作详细说明(后面会出现)。 |
setEntry(在下面的示例中)被标记为public,但可以改为external以略微节省 gas。
状态交互修饰符
| Modifier | 行为 |
|---|---|
view | 可以 读取 状态变量,但 不能修改。离链调用时(例如通过 Etherscan)不消耗 gas。 |
pure | 不能读取或修改状态。只能使用其输入和局部变量。 |
示例函数
function getDay() public view returns (uint256) {
return dayNumber;
}
function add(uint256 a, uint256 b) public pure returns (uint256) {
return a + b;
}
4️⃣ 项目:Web3 旅程记录器
与另一个通用的 “Simple Storage” 示例不同,我们将构建一个 Web3 旅程记录器 合约,直接与本学习挑战相结合。
合约功能
- 存储名称(你的学习者昵称)。
- 存储当前学习天数。
- 存储当天的简短笔记。
核心行为
| 行为 | 描述 |
|---|---|
| 所有者 | 部署时会记住部署者(owner)。 |
| 更新 | 允许更新最新条目的 dayNumber 和 note。 |
| 读取 | 任何人都可以读取存储的值(name、dayNumber、note)。 |
这些行为可以简洁地映射到少量状态变量和两到三个函数。
5️⃣ 完整合约代码
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Web3JourneyLogger {
// ── State variables ──
/// @notice Address of the person who deployed the contract
address public owner;
/// @notice Name or handle of the learner
string public name;
/// @notice Current day in the learning journey
uint256 public dayNumber;
/// @notice Short note for the current day
string public note;
// ── Constructor ──
/**
* @dev Sets the contract deployer as `owner` and initializes the learner's `name`.
* @param _name The learner's name or handle.
*/
constructor(string memory _name) {
owner = msg.sender;
name = _name;
}
// ── Core functions ──
/**
* @dev Updates the current day number and an optional note.
* Only the contract `owner` can call this function.
* @param _day New day number.
* @param _note Short note for the day.
*/
function setEntry(uint256 _day, string calldata _note) external {
require(msg.sender == owner, "Only owner can update");
dayNumber = _day;
note = _note;
}
/**
* @dev Returns the stored learner information.
* @return _name Learner's name.
* @return _day Current day number.
* @return _note Current note.
*/
function getEntry()
external
view
returns (string memory _name, uint256 _day, string memory _note)
{
return (name, dayNumber, note);
}
}
工作原理
| 函数 | 可见性 | 状态交互 | 谁可以调用? |
|---|---|---|---|
constructor | public(仅执行一次) | 写入 owner 与 name | 部署者 |
setEntry | external | 写入 dayNumber 与 note(仅限 owner) | 仅所有者 |
getEntry | external view | 读取 所有公开变量 | 任意人 |
将此合约部署到 Sepolia(或任何兼容 EVM 的测试网),即可拥有一份个人链上日志,记录你的 Web3 学习旅程。
6️⃣ 下一步
- Compile & Deploy 合约,使用 Remix、Hardhat 或 Foundry。
- Interact
setEntry,记录新的一天和备注。 - Read 数据,可通过
getEntry或直接使用自动生成的 getter(owner(),name(),dayNumber(),note())读取。
这就是第 26 天的全部内容!现在你已经拥有了一个具体示例,展示了 变量 与 函数 如何组合成可用的链上应用。明天我们将深入更复杂的数据结构(映射、结构体),并探讨如何让你的合约更安全、更省 gas。祝编码愉快!
Web3 Journey Logger – 一个简约的 Solidity 合约
下面是一个简单的 Solidity 合约,用于记录每日条目(天数和简短备注)。它演示了:
- 状态变量和构造函数
- 带基本访问控制的状态改变函数
- 返回多个值的 view 函数
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Web3JourneyLogger {
address public owner;
string public name;
uint256 public dayNumber;
string public note;
// Constructor – runs once when the contract is deployed
constructor(string memory _name) {
owner = msg.sender;
name = _name;
}
// Update the current day and note (only the owner can call)
function setEntry(uint256 _dayNumber, string calldata _note) public {
require(msg.sender == owner, "Not owner");
dayNumber = _dayNumber;
note = _note;
}
// Helper to read all data in one call
function getEntry()
public
view
returns (
string memory _name,
uint256 _day,
string memory _note
)
{
return (name, dayNumber, note);
}
}
这个简约合约演示了状态变量、构造函数、带简单访问控制检查的状态改变函数,以及返回多个值的 view 函数。
Source: …
在 Remix 与 MetaMask 上部署到 Sepolia
前置条件
- 在浏览器中已安装 MetaMask(或其他 Web3 钱包)。
- 钱包必须 连接到 Sepolia 测试网络。
- 从 Sepolia 水龙头获取少量 测试 ETH,用于支付部署 gas。
步骤指南
- 打开 Remix —— 一个基于浏览器的 Solidity IDE。
- 创建新文件
- 在文件资源管理器中点击 +,并将文件命名为
Web3JourneyLogger.sol。
- 在文件资源管理器中点击 +,并将文件命名为
- 粘贴合约代码(上面的代码片段)到该文件中。
- 编译合约
- 打开 Solidity Compiler 选项卡。
- 选择与 pragma 匹配的编译器版本,例如 0.8.20。
- 点击 Compile Web3JourneyLogger.sol。
- 部署到 Sepolia
- 打开 Deploy & Run Transactions 选项卡。
- 将 Environment 设置为 Injected Provider – MetaMask。
- 确认 MetaMask 已切换到 Sepolia 网络。
- 确保在 Contract 下拉框中选中
Web3JourneyLogger。 - 在 Constructor Arguments 字段中输入一个名称字符串,例如
"Ribhav"。 - 点击 Deploy 并在 MetaMask 中确认交易。
- 验证部署
- 交易被打包后,Remix 会在 Deployed Contracts 区域显示你的合约实例。
- 你可以使用交易哈希在 Sepolia Etherscan 上查看该交易。
- 与合约交互
- 在 Deployed Contracts 下展开已部署的实例。
- 调用自动生成的 getter(
owner、name、dayNumber、note)查看当前值。 - 使用
setEntry存储新的日期编号和备注(仅所有者可调用)。 - 再次通过各个 getter 或
getEntry只读函数检索数据。
通过每日重复上述操作,合约将成为你 Web3 学习之旅的一个小型链上日志。
为什么这很重要
每个 DeFi 协议、NFT 市场或 DAO 本质上都是比这里介绍的变量和函数更复杂的组合。理解:
- 状态如何存储
- 函数如何暴露或保护该状态
- 合约如何部署到网络上
是安全智能合约开发和审计的基础。
后续步骤将扩展到 数组、映射、结构体、访问控制模式,以及诸如 Hardhat 和 Foundry 等本地开发工具——所有这些都建立在本篇 Solidity 文章提出的核心概念之上。
进一步阅读
- Solidity 官方文档 – 智能合约简介
- Solidity 示例 – 简单存储与基础
- GeeksforGeeks – Solidity 合约基础
- GeeksforGeeks – Solidity 变量
- GeeksforGeeks – Solidity 函数
- Dapp University – Solidity 入门
保持联系
- 在 Medium、Twitter 和 Future 上关注本系列
- 加入 Telegram 上的 Web3ForHumans —— 一起头脑风暴 Web3!