【Solidity 从入门到精通】第3章 Solidity 基础语法详解 - 详解

本章将深入讲解 Solidity 的语言结构与基本语法,让你从“能看懂”走向“能写出”。我们将探索变量、数据类型、函数、可见性、事件、修饰符等概念,用生动的比喻、清晰的表格和实战示例帮助你理解。通过构建一个简单的“留言墙(Message Wall)”智能合约,你将掌握状态与内存变量的区别、函数的 Gas 成本、事件的日志机制,以及 Solidity 编程的独特思维方式。这一章是你成为 Solidity 开发者的真正起点。

关键词: 变量作用域、数据类型、函数修饰符、事件、状态管理


3.1 语言基础概览:Solidity 的语法风格

“Solidity 看起来像 JavaScript,却更像法律文件。”

Solidity 的语法灵感来源于 JavaScript、C++ 和 Python。
它像 JS 一样使用大括号 {},但又像 C 一样严格定义类型。

如果你熟悉这些语言,你会觉得 Solidity “似曾相识”,但又“处处不同”。


Solidity 与常见语言语法对比

特性JavaScriptSolidity备注
变量声明let a = 1;uint a = 1;Solidity 要声明类型
数组[1, 2, 3]uint[] nums = [1,2,3];固定/动态长度皆可
字符串"hello""hello"字符串不能直接拼接
函数定义function add(a,b){}function add(uint a, uint b) public returns(uint){}必须声明可见性与返回值
classcontract合约即类

Solidity 就像“严格模式的 JavaScript”,
但它运行在全球分布式计算机网络上


3.2 数据类型与变量:区块链上的存储单位

“每一个变量,都是写进账本的墨迹。”

Solidity 中的主要数据类型

类型分类示例说明
整数类型uint256, int8uint 表示无符号整数(0或正数)
布尔类型booltruefalse
地址类型address表示账户地址(钱包/合约)
字符串string存储文本
固定字节数组bytes1 ~ bytes32固定长度的二进制数据
动态数组uint[], string[]可扩展集合
映射(mapping)mapping(address => uint)类似字典或哈希表
结构体(struct)自定义类型类似类的简单形式

状态变量与局部变量

  • 状态变量(State Variable)
    保存在区块链上,修改它需要交易与 Gas。
  • 局部变量(Local Variable)
    保存在内存中,只在函数执行时存在,不上链。
pragma solidity ^0.8.0;
contract VariableDemo {
    uint public counter = 0; // 状态变量
    function increase() public {
        uint temp = counter; // 局部变量
        temp += 1;
        counter = temp; // 写回区块链(消耗 Gas)
    }
}
操作类型存储位置是否消耗 Gas生命周期
状态变量区块链存储(storage)✅ 是永久保存
局部变量内存(memory)❌ 否函数执行期间
常量编译时写死❌ 否永久不变

“Storage、Memory、Calldata”的区别图解

+----------------------------------------------------------+
| 区块链永久存储 (Storage) → 状态变量                     |
| 函数临时存储 (Memory) → 临时对象                        |
| 只读外部数据 (Calldata) → 外部函数参数                  |
+----------------------------------------------------------+

可简单理解为:

  • storage:存到硬盘;
  • memory:存到内存;
  • calldata:传参快递箱。

3.3 函数与可见性修饰符

“在 Solidity 世界中,函数不仅定义行为,也定义信任边界。”

函数的定义格式

function functionName(type parameter)
    visibility
    stateMutability
    returns(type)
{
    // 函数体
}

例如:

function add(uint a, uint b) public pure returns(uint) {
    return a + b;
}

可见性(Visibility)关键字

修饰符说明谁能调用类比
public任何人可调用所有用户与合约公共服务
external仅外部调用外部账户API 接口
internal合约内部可见继承合约保护函数
private当前合约内部无法继承私有函数

状态修饰符(State Mutability)

关键字说明是否修改状态是否消耗 Gas
pure不读不写
view只读
(无修饰)可写
payable可接收 ETH

示例:

function getCounter() public view returns(uint) {
    return counter;
}
function add(uint a, uint b) public pure returns(uint) {
    return a + b;
}
function receiveEther() public payable {
    // 可接收 ETH
}

3.4 修饰符(Modifier):智能合约的“守门员”

“Modifier 是 Solidity 的防线,用来设定进入规则。”

修饰符(modifier)允许你在函数执行前后添加条件逻辑。
比如:只有管理员能执行某个函数。

modifier onlyOwner() {
    require(msg.sender == owner, "Not authorized");
    _;
}

_ 表示函数主体在此处执行。
在函数中使用:

function withdraw() public onlyOwner {
    payable(owner).transfer(address(this).balance);
}

执行流程图:

调用函数 → 检查 onlyOwner → 如果通过 → 执行函数体

(图3-1:Modifier 执行流程)


3.5 事件(Event):区块链的日志系统

“区块链没有数据库,但它有事件日志。”

事件是 Solidity 用来在区块链上记录活动的机制。
类似于后端日志(log),但会被写入链上。

event NewMessage(address indexed sender, string content);
function postMessage(string memory content) public {
    emit NewMessage(msg.sender, content);
}

事件会在区块中被永久记录,可被 DApp 前端监听。
前端可通过 ethers.jsweb3.js 读取事件日志。


事件元素说明
event声明事件
emit触发事件
indexed可检索字段
区块日志可供前端监听

3.6 实战项目:构建一个“留言墙(Message Wall)”智能合约

“从一句留言,开始你的链上交流。”

让我们结合本章所学,写一个完整可运行的项目。
这个合约允许用户:

  • 留下留言;
  • 记录留言者地址;
  • 触发事件;
  • 读取所有留言。

合约代码

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract MessageWall {
    struct Message {
        address sender;
        string text;
        uint timestamp;
    }
    Message[] public messages;
    address public owner;
    event NewMessage(address indexed sender, string text, uint timestamp);
    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }
    constructor() {
        owner = msg.sender;
    }
    function postMessage(string memory _text) public {
        messages.push(Message(msg.sender, _text, block.timestamp));
        emit NewMessage(msg.sender, _text, block.timestamp);
    }
    function getMessagesCount() public view returns (uint) {
        return messages.length;
    }
    function clearMessages() public onlyOwner {
        delete messages;
    }
}

功能说明表

函数功能修饰符Gas 成本
postMessage()发布新留言
getMessagesCount()查询留言数view
clearMessages()删除所有留言onlyOwner

运行逻辑示意图

用户 → postMessage() → 写入 messages[] → emit NewMessage() → 区块链事件日志

(图3-2:MessageWall 执行流程)


3.7 区块链思维:为什么写入成本高?

“区块链上的每一个字节,都是全球共识的成本。”

当你写入一条留言时:

  • 所有节点都要保存这条信息;
  • 共识算法要验证这条交易;
  • 因此写入成本(Gas)远高于传统数据库。

阅读(view)是免费的,写入是昂贵的。

这也引出了区块链的设计哲学:
计算要轻,存储要少,逻辑要明。


3.8 小结与思考

本章你学会了:

  • Solidity 的基本语法与类型;
  • 函数可见性与状态修饰符;
  • 使用修饰符定义权限;
  • 事件机制;
  • 构建完整留言墙项目。

思考练习

  1. MessageWall 添加一个 like 功能,每条留言可被点赞。
  2. 实现留言分页查询函数。
  3. 使用事件记录点赞行为。
  4. 通过 MetaMask 将合约部署到测试网。

下一章预告:

第4章《Solidity 进阶特性与合约间交互》
我们将探索继承、多态、接口(Interface)、抽象合约、库(Library),以及合约之间如何互相调用。
这将是从“代码逻辑”迈向“智能生态”的关键一步。

posted @ 2025-12-01 08:14  gccbuaa  阅读(10)  评论(0)    收藏  举报