Solidity 基础(第1部分)——变量、函数与你的第一个真实合约

发布: (2026年1月5日 GMT+8 15:05)
13 min read
原文: Dev.to

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 条件等。

两个关键区别:

  1. 你编写的是 金钱和状态,而不仅仅是 UI。
  2. 每一次操作都要消耗 gas,且你部署的代码大多是 永久 的。

Source:

2️⃣ 变量 – 合约的内存

把智能合约想象成一个拥有自己私有数据库的链上小应用。变量就是合约存储数据的命名盒子。

在 Solidity 中,你必须始终声明变量的类型和名称,因为编译器需要确切知道要把什么存在哪里。

三种层级的变量

级别作用域持久性典型用法
状态变量永久存储在区块链上的合约存储中。在函数调用和交易之间保持。所有者地址、代币余额映射、计数器。
局部变量在函数内部声明。仅在该函数运行期间存在,随后消失。uint256 sum = a + b; 在函数内部使用。
全局变量由 EVM 提供的内置助手。在执行期间只能读取。msg.senderblock.timestampblock.number

在这一步我们重点关注 状态变量,因为它们构成了合约的链上内存。

核心数据类型(几乎每个合约都会用到的)

类型描述示例
bool存储 truefalsebool public completed;
uint256无符号整数(0 及正数)。常用于金额、ID、计数器、时间戳。uint256 public dayNumber;
address存储以太坊地址(用户或合约)。address public owner;
string存储文本数据。相较于数字消耗更多 gas,只有在需要时才使用。string public note;

还有很多其他类型(intbytesmappingstruct、数组等),但这四种足以让你入门。

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 旅程记录器 合约,直接与本学习挑战相结合。

合约功能

  1. 存储名称(你的学习者昵称)。
  2. 存储当前学习天数
  3. 存储当天的简短笔记

核心行为

行为描述
所有者部署时会记住部署者(owner)。
更新允许更新最新条目的 dayNumbernote
读取任何人都可以读取存储的值(namedayNumbernote)。

这些行为可以简洁地映射到少量状态变量和两到三个函数。

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);
    }
}

工作原理

函数可见性状态交互谁可以调用?
constructorpublic(仅执行一次)写入 ownername部署者
setEntryexternal写入 dayNumbernote(仅限 owner仅所有者
getEntryexternal view读取 所有公开变量任意人

将此合约部署到 Sepolia(或任何兼容 EVM 的测试网),即可拥有一份个人链上日志,记录你的 Web3 学习旅程。

6️⃣ 下一步

  1. Compile & Deploy 合约,使用 Remix、Hardhat 或 Foundry。
  2. Interact setEntry,记录新的一天和备注。
  3. 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

前置条件

  1. 在浏览器中已安装 MetaMask(或其他 Web3 钱包)。
  2. 钱包必须 连接到 Sepolia 测试网络
  3. 从 Sepolia 水龙头获取少量 测试 ETH,用于支付部署 gas。

步骤指南

  1. 打开 Remix —— 一个基于浏览器的 Solidity IDE。
  2. 创建新文件
    • 在文件资源管理器中点击 +,并将文件命名为 Web3JourneyLogger.sol
  3. 粘贴合约代码(上面的代码片段)到该文件中。
  4. 编译合约
    • 打开 Solidity Compiler 选项卡。
    • 选择与 pragma 匹配的编译器版本,例如 0.8.20
    • 点击 Compile Web3JourneyLogger.sol
  5. 部署到 Sepolia
    • 打开 Deploy & Run Transactions 选项卡。
    • Environment 设置为 Injected Provider – MetaMask
    • 确认 MetaMask 已切换到 Sepolia 网络
    • 确保在 Contract 下拉框中选中 Web3JourneyLogger
    • Constructor Arguments 字段中输入一个名称字符串,例如 "Ribhav"
    • 点击 Deploy 并在 MetaMask 中确认交易。
  6. 验证部署
    • 交易被打包后,Remix 会在 Deployed Contracts 区域显示你的合约实例。
    • 你可以使用交易哈希在 Sepolia Etherscan 上查看该交易。
  7. 与合约交互
    • Deployed Contracts 下展开已部署的实例。
    • 调用自动生成的 getter(ownernamedayNumbernote)查看当前值。
    • 使用 setEntry 存储新的日期编号和备注(仅所有者可调用)。
    • 再次通过各个 getter 或 getEntry 只读函数检索数据。

通过每日重复上述操作,合约将成为你 Web3 学习之旅的一个小型链上日志。

为什么这很重要

每个 DeFi 协议、NFT 市场或 DAO 本质上都是比这里介绍的变量和函数更复杂的组合。理解:

  • 状态如何存储
  • 函数如何暴露或保护该状态
  • 合约如何部署到网络上

是安全智能合约开发和审计的基础。

后续步骤将扩展到 数组、映射、结构体、访问控制模式,以及诸如 HardhatFoundry 等本地开发工具——所有这些都建立在本篇 Solidity 文章提出的核心概念之上。

进一步阅读

  • Solidity 官方文档 – 智能合约简介
  • Solidity 示例 – 简单存储与基础
  • GeeksforGeeks – Solidity 合约基础
  • GeeksforGeeks – Solidity 变量
  • GeeksforGeeks – Solidity 函数
  • Dapp University – Solidity 入门

保持联系

  • MediumTwitterFuture 上关注本系列
  • 加入 Telegram 上的 Web3ForHumans —— 一起头脑风暴 Web3!
Back to Blog

相关文章

阅读更多 »