第3章:智能合约入门:Solidity语言概览、合约结构、第一个HelloWorld合约
好,我们正式开始写代码了。
前面两章聊了Web3的宏观图景和开发环境搭建。现在,是时候亲手触碰智能合约了。我个人觉得,学任何语言,第一个程序都应该是「Hello World」。这不仅是仪式感,更是让你快速感知「这东西到底怎么跑起来」的最短路径。
3.1 Solidity:以太坊上的「官方语言」
Solidity,说白了就是专门给以太坊写智能合约用的。它长得有点像JavaScript,但骨子里完全不一样。你想想看,JS跑在浏览器里,而Solidity跑在区块链上——这就决定了它必须「一次部署,永不修改」。
我在项目中遇到过不少新手,上来就用JS的思维写Solidity,结果踩了一堆坑。比如循环里改状态变量,这在Solidity里可是要命的操作——gas费高得离谱。
核心要点:Solidity是静态类型语言,编译后生成EVM(以太坊虚拟机)字节码。它不支持浮点数,也没有标准库里的「随机数」——因为区块链是确定性的。
3.2 合约结构:一个智能合约长什么样?
一个标准的Solidity合约,通常包含这几部分。我习惯按这个顺序写,清晰又不容易漏东西。
| 组成部分 | 说明 | 我的经验 |
|---|---|---|
| SPDX许可证标识 | 声明代码的开源许可 | 不写的话,编译会警告。我一般用MIT |
| Pragma指令 | 指定Solidity编译器版本 | 千万别写^0.8.0这种太宽泛的版本 |
| Import语句 | 引入其他合约或库 | 尽量少用,减少依赖 |
| 合约声明 | contract关键字 + 合约名 | 合约名首字母大写,这是行业惯例 |
| 状态变量 | 存储在链上的数据 | 注意可见性:public/private/internal |
| 构造函数 | 部署时执行一次 | 可以用来初始化owner等 |
| 函数 | 合约的行为逻辑 | 记得加访问修饰符 |
| 事件 | 链上日志,供前端监听 | 能省gas就省,但调试时很有用 |
| 修饰器 | 函数执行前的检查 | 我最常用的是onlyOwner |
小技巧:写合约时,我习惯先把结构骨架搭好,再往里填逻辑。就像写作文先列提纲一样,不容易跑偏。
3.3 第一个HelloWorld合约
好了,直接上代码。这是你能写出来的第一个真正意义上的智能合约。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
contract HelloWorld {
// 状态变量:存储在链上
string public greeting;
// 构造函数:部署时执行一次
constructor() {
greeting = "Hello, Web3!";
}
// 读取函数:不消耗gas(view关键字)
function getGreeting() public view returns (string memory) {
return greeting;
}
// 写入函数:消耗gas,改变链上状态
function setGreeting(string memory _newGreeting) public {
greeting = _newGreeting;
}
}
嗯,这里要注意几个点。
第一,string public greeting 这行。加了 public 关键字后,Solidity会自动生成一个同名的getter函数。也就是说,你不用自己写 getGreeting() 也能读到 greeting 的值。但我还是习惯显式写出来,方便加注释。
第二,view 关键字。它告诉编译器:这个函数只读不写。调用它不需要花gas。我曾经见过有人把 view 函数写成普通函数,结果每次调用都扣gas,白白浪费钱。
第三,memory 关键字。在Solidity里,string 是引用类型,必须指定数据位置。函数参数和返回值用 memory,状态变量自动用 storage。这个规则我刚开始也搞混过,后来记住一句话:「参数用memory,变量用storage」。
避坑指南:我曾经在写setGreeting函数时,忘了加 public 修饰符。结果部署后,前端死活调不到这个函数。排查了半天才发现——Solidity默认函数可见性是 internal,外部根本调不了。所以,写函数时第一件事就是确认可见性。
3.4 部署与交互:让合约真正跑起来
写完了合约,怎么验证它能不能跑?我建议用Remix IDE,在线就能编译部署,不用搭本地环境。
- 打开 remix.ethereum.org(别担心,这是个在线IDE)
- 新建文件,命名为
HelloWorld.sol - 把上面的代码粘贴进去
- 点击「Solidity Compiler」选项卡,编译
- 切换到「Deploy & Run Transactions」选项卡
- 环境选「Remix VM」(模拟器,不花真钱)
- 点击「Deploy」按钮
- 在下方「Deployed Contracts」里找到你的合约
- 点击
greeting或getGreeting()查看结果 - 在
setGreeting输入框里填个新字符串,点击调用 - 再查一次
greeting,看看变了没
你想想看,整个过程不到两分钟。但背后发生了什么?
- Solidity代码被编译成了EVM字节码
- 字节码被部署到虚拟机的区块链上
- 你调用函数时,实际上是在向区块链发送交易
- 交易被矿工打包,状态变量被永久存储
关键认知:一旦部署,合约代码就不可更改。但状态变量可以改——这就是「不可变逻辑,可变数据」的核心思想。我刚开始做项目时,总想着「先部署再改bug」,结果发现合约改不了,只能重新部署一个新地址。所以,测试一定要充分。
3.5 从HelloWorld到真实项目
这个HelloWorld合约虽然简单,但它包含了智能合约的所有核心要素:状态存储、读写函数、可见性控制、gas消耗机制。
我个人建议,你可以在这个基础上做几个小实验:
- 加一个计数器,每次调用加1
- 加一个owner地址,只有owner能修改greeting
- 加一个事件,每次修改时触发
这些练习做完,你对Solidity的基本语法和合约结构就有感觉了。下一章,我们会深入讲数据类型和变量——嗯,那才是真正开始「玩」Solidity的时候。
课后作业:把上面的HelloWorld合约部署到Remix VM上,然后尝试调用setGreeting改成你自己的名字。再查一下greeting,看看是不是变了。如果没变,检查一下是不是忘了点「Transact」按钮——我当年就犯过这个低级错误。