3、Solidity语言入门:Solidity简介、开发环境(Remix IDE)、第一个智能合约(Hello World)、合约结构
好,咱们正式开始写代码了。
前面两章聊了NFT是什么、ERC-721标准怎么来的,算是热身。从这一章开始,我们要真正动手了。你想想看,一个智能合约工程师,最趁手的兵器是什么?就是Solidity这门语言。
3.1 Solidity 到底是什么?
Solidity,说白了就是用来写以太坊智能合约的一门高级语言。它长得有点像JavaScript,也带点C++的影子。我刚开始学的时候,第一反应是:“这不就是JS加了个类型系统吗?” 嗯,后来发现事情没那么简单。
它有几个关键特点,我挑重要的说:
- 面向合约:不是面向对象,是面向合约。每个合约就像一个独立的“小程序”,部署到链上后就永远跑在那里。
- 静态类型:变量类型在编译时就定死了。你不能像JS那样随便把数字赋给字符串变量——编译器会直接报错。
- 图灵完备:理论上你能用Solidity写出任何逻辑。但Gas限制会教你做人,哈哈。
- 编译部署:写好的代码不能直接跑,得先编译成EVM(以太坊虚拟机)能理解的字节码,然后部署上链。
3.2 开发环境:Remix IDE
工欲善其事,必先利其器。我推荐新手直接用Remix IDE。这是一个在线的Solidity开发环境,打开浏览器就能用,不需要装任何东西。
地址是:https://remix.ethereum.org/(放心,我不会让你点链接,自己搜一下就行)。
Remix 的界面分三块:
- 左侧文件区:管理你的.sol文件。默认会有一个
contracts文件夹,里面有几个示例合约。 - 中间编辑区:写代码的地方。支持语法高亮、自动补全,挺方便的。
- 右侧功能区:编译、部署、调试都在这里。有个“编译”按钮,点一下就能看到有没有语法错误。
我记得第一次用Remix时,最让我惊讶的是它内置了一个虚拟的以太坊环境。你不需要真的花钱买ETH,就能在浏览器里模拟部署和调用合约。这对学习来说太友好了。
3.3 第一个智能合约:Hello World
好了,咱们来写第一个合约。按照程序员的传统,先来个 Hello World。
在 Remix 里新建一个文件,命名为 HelloWorld.sol,然后输入以下代码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract HelloWorld {
string public greeting = "Hello, NFT World!";
function sayHello() public view returns (string memory) {
return greeting;
}
function setGreeting(string memory _newGreeting) public {
greeting = _newGreeting;
}
}
来,一行一行拆开看:
// SPDX-License-Identifier: MIT—— 这是开源许可证声明。Solidity 编译器要求你必须写这个,不然会警告。我一般用 MIT,简单粗暴。pragma solidity ^0.8.0;—— 声明编译器版本。^0.8.0 表示兼容 0.8.x 的所有小版本。为什么要有这个?因为不同版本的 Solidity 语法可能有差异,防止你的代码被错误的编译器编译。contract HelloWorld { ... }—— 定义一个合约。合约名首字母大写,这是惯例。string public greeting—— 声明一个公开的状态变量。public 关键字会自动生成一个同名的 getter 函数,方便外部读取。function sayHello() public view returns (string memory)—— 一个只读函数。view 表示这个函数不会修改链上状态,所以调用它不需要花 Gas。function setGreeting(...) public—— 一个写入函数。它会修改 greeting 的值,所以调用它需要支付 Gas。
public 变量会自动生成 getter,但不会自动生成 setter。如果你想修改它,必须自己写函数。这是出于安全考虑——你想想看,如果所有变量都能随便改,那合约还有什么安全性可言?
3.4 合约结构:骨架与血肉
写了一个完整的合约,咱们来总结一下 Solidity 合约的基本结构。说白了,一个合约就像一栋房子,有固定的骨架,你往里面填内容就行。
一个标准的 Solidity 合约包含以下几个部分:
| 组成部分 | 说明 | 是否必须 |
|---|---|---|
| SPDX 许可证 | 声明开源协议 | 强烈建议 |
| Pragma 指令 | 指定编译器版本 | 必须 |
| Import 语句 | 引入其他合约或库 | 按需 |
| 合约定义 | contract 合约名 { ... } |
必须 |
| 状态变量 | 存储在链上的数据 | 按需 |
| 函数 | 合约的行为逻辑 | 按需 |
| 修饰器 | 用于权限控制等 | 按需 |
| 事件 | 链上日志,用于外部监听 | 按需 |
| 错误定义 | 自定义错误信息 | 按需 |
我个人的习惯是,写合约时先搭骨架:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract MyContract {
// 1. 状态变量
// 2. 事件
// 3. 修饰器
// 4. 构造函数
// 5. 外部函数
// 6. 内部函数
}
为什么要按这个顺序?因为 Solidity 的编译器对声明顺序没有强制要求,但团队协作时,统一的代码风格能减少很多不必要的沟通成本。我曾经在一个项目里看到有人把状态变量写在函数后面,找起来真的很痛苦。
3.5 编译与部署:见证奇迹的时刻
代码写完了,怎么跑起来?在 Remix 里很简单:
- 点击右侧的“Solidity Compiler”标签(就是那个带“S”的图标)。
- 确保编译器版本和 pragma 声明的一致。比如你写了
^0.8.0,就选 0.8.x 的版本。 - 点击“Compile HelloWorld.sol”。如果没报错,你会看到一个绿色的勾。
- 切换到“Deploy & Run Transactions”标签(那个以太坊图标)。
- 环境选“Remix VM (Shanghai)”,然后点击“Deploy”。
- 部署成功后,下面会出现你的合约实例。点开它,就能看到
greeting和sayHello按钮了。
点一下 greeting 或 sayHello,你会看到返回 "Hello, NFT World!"。再试试 setGreeting,输入 "Hello, Solidity!",然后再次调用 greeting,你会发现值变了。
嗯,这就是智能合约的魔力。你刚刚在区块链上(虽然是模拟的)部署了一个永不停机的程序。
记住,写智能合约和写普通程序最大的区别是:代码一旦上链,就几乎无法修改。所以,每写一行代码,都要问自己:“这个逻辑真的对吗?有没有漏洞?” 我见过太多因为少写一个检查而导致资产被盗的案例了。
好,今天就到这里。去 Remix 里敲一敲代码,感受一下。下一章见。