Solidity 语法速查手册
涵盖所有核心语法:数据类型、函数、修饰符、事件、继承、错误处理等
1. Solidity 简介
Solidity 是以太坊智能合约的主流编程语言,语法类似 JavaScript,面向对象,静态类型。
核心特性
- 静态类型 - 编译时类型检查
- 面向对象 - 支持继承、接口、抽象合约
- EVM 字节码 - 编译为以太坊虚拟机字节码
- 内置区块链特性 - msg.sender、block.timestamp 等全局变量
版本说明
- 当前稳定版:^0.8.x(推荐)
- 0.8.0+ 默认开启溢出检查
- 使用 pragma 指定版本:pragma solidity ^0.8.20;
2. 合约结构
一个 Solidity 合约包含:状态变量、函数、修饰符、事件、错误、结构体、枚举等。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyContract is Ownable {
// State variables
uint256 public count;
mapping(address => uint256) public balances;
// Events
event CountIncreased(uint256 newCount);
// Errors
error InsufficientBalance(uint256 requested, uint256 available);
// Modifiers
modifier onlyPositive(uint256 value) {
require(value > 0, "Value must be positive");
_;
}
// Constructor
constructor() Ownable(msg.sender) {
count = 0;
}
// Functions
function increment() public onlyPositive(1) {
count++;
emit CountIncreased(count);
}
}合约组成部分
- License & Pragma - 许可证和版本声明
- Import - 导入其他合约
- State Variables - 状态变量(存储在链上)
- Functions - 函数(external/public/internal/private)
- Modifiers - 修饰符(函数执行前/后的检查)
- Events - 事件(用于日志记录)
- Errors - 自定义错误(0.8.4+)
- Struct & Enum - 自定义数据结构
3. 数据类型
Solidity 支持值类型和引用类型。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract DataTypesDemo {
// Value Types
bool public isActive = true;
uint256 public myUint = 123;
int256 public myInt = -456;
address public myAddress = 0x1234567890123456789012345678901234567890;
address payable public myPayableAddress = payable(msg.sender);
bytes32 public myBytes32 = "Hello";
// Reference Types
string public myString = "Hello World";
bytes public myDynamicBytes = "Dynamic";
uint256[] public myArray;
mapping(address => uint256) public myMapping;
struct Person {
string name;
uint256 age;
}
Person public myPerson = Person("Alice", 30);
enum Status { Pending, Active, Closed }
Status public currentStatus = Status.Pending;
// Data locations
function dataLocationExample(string memory _str) public pure returns (string memory) {
// memory: temporary, cheap
string memory tempStr = _str;
return tempStr;
}
function dataLocationExample2(uint256[] calldata _arr) external pure returns (uint256) {
// calldata: read-only, cheapest for external functions
return _arr[0];
}
}值类型(Value Types)
bool- true / falseuint8 ~ uint256- 无符号整数(uint 默认 uint256)int8 ~ int256- 有符号整数address- 20字节以太坊地址address payable- 可接收 ETH 的地址bytes1 ~ bytes32- 固定长度字节数组enum- 枚举类型
引用类型(Reference Types)
string- 动态长度 UTF-8 字符串bytes- 动态长度字节数组array- 数组(T[] 或 T[5])mapping- 映射(哈希表)struct- 结构体
数据位置
storage- 永久存储(状态变量,gas 高)memory- 临时存储(函数参数/返回值,gas 低)calldata- 只读临时存储(external 函数参数,gas 最低)
4. 变量与常量
Solidity 有三种变量类型:状态变量、局部变量、全局变量。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract VariablesDemo {
// State variables (stored on-chain)
uint256 public stateVar = 100;
// Constants (compile-time, save gas)
uint256 public constant MY_CONSTANT = 123;
address public constant OWNER = 0x1234567890123456789012345678901234567890;
// Immutable (deploy-time, save gas)
uint256 public immutable DEPLOY_TIMESTAMP;
address public immutable DEPLOYER;
constructor() {
DEPLOY_TIMESTAMP = block.timestamp;
DEPLOYER = msg.sender;
}
function globalVariablesExample() public payable returns (
address sender,
uint256 value,
uint256 timestamp,
uint256 blockNumber,
uint256 contractBalance
) {
// Global variables
sender = msg.sender; // caller address
value = msg.value; // ETH sent (in wei)
timestamp = block.timestamp; // current block time
blockNumber = block.number; // current block number
contractBalance = address(this).balance;
}
}状态变量(State Variables)
- 存储在链上,消耗 gas
- 默认 internal 可见性
- 可用 public/private/internal 修饰
常量(Constants & Immutable)
constant- 编译时常量,必须赋值为常量表达式immutable- 部署时常量,可在 constructor 中赋值两者都节省 gas(不占用 storage slot)-
全局变量(Global Variables)
msg.sender- 调用者地址msg.value- 发送的 ETH 数量(wei)block.timestamp- 当前区块时间戳block.number- 当前区块号tx.gasprice- 交易 gas 价格address(this).balance- 合约余额
5. 函数
函数是智能合约的核心逻辑。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract FunctionsDemo {
uint256 public count;
// Visibility modifiers
function publicFunc() public { count++; } // callable by anyone
function externalFunc() external { count++; } // only external calls
function internalFunc() internal { count++; } // only this contract + derived
function privateFunc() private { count++; } // only this contract
// State mutability
function viewFunc() public view returns (uint256) {
return count; // read-only
}
function pureFunc(uint256 a, uint256 b) public pure returns (uint256) {
return a + b; // no state access
}
function payableFunc() public payable {
// can receive ETH
}
// Return values
function multipleReturns() public pure returns (uint256, bool, string memory) {
return (123, true, "hello");
}
function namedReturns() public pure returns (uint256 x, bool y) {
x = 456;
y = false;
}
// Special functions
constructor() {
count = 0; // runs once at deployment
}
receive() external payable {
// called when ETH sent with no data
}
fallback() external payable {
// called when function doesn't exist
}
}可见性(Visibility)
public- 内部和外部都可调用external- 仅外部调用(gas 更省)internal- 仅当前合约和子合约private- 仅当前合约
状态可变性(State Mutability)
view- 只读函数,不修改状态pure- 纯函数,不读不写状态payable- 可接收 ETH默认- 可读写状态
特殊函数
constructor- 部署时执行一次receive- 接收 ETH(无 data)fallback- 找不到函数时调用
6. 修饰符 (Modifier)
Modifier 用于在函数执行前/后进行检查,类似装饰器。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract ModifiersDemo {
address public owner;
bool public paused;
mapping(address => bool) public whitelist;
constructor() {
owner = msg.sender;
}
// Access control modifier
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_; // function body executes here
}
// State check modifier
modifier whenNotPaused() {
require(!paused, "Contract is paused");
_;
}
// Input validation modifier
modifier validAddress(address _addr) {
require(_addr != address(0), "Invalid address");
require(_addr != address(this), "Cannot be contract address");
_;
}
// Multiple modifiers
function sensitiveAction(address _to)
public
onlyOwner
whenNotPaused
validAddress(_to)
{
// modifiers execute in order: onlyOwner -> whenNotPaused -> validAddress
whitelist[_to] = true;
}
// Modifier with return value (runs after function)
modifier logExecution() {
_;
emit ActionExecuted(msg.sender, block.timestamp);
}
event ActionExecuted(address indexed user, uint256 timestamp);
}常见用途
- 权限控制(onlyOwner)
- 输入验证(检查参数合法性)
- 重入保护(nonReentrant)
- 状态检查(合约是否暂停)
_; 的作用
_; 表示被修饰函数的执行位置。在 _; 之前的代码在函数执行前运行,之后的代码在函数执行后运行。
7. 事件 (Event)
事件用于记录链上日志,前端可监听事件获取实时数据。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract EventsDemo {
// Event declaration
event Transfer(address indexed from, address indexed to, uint256 amount);
event Deposit(address indexed user, uint256 amount, uint256 timestamp);
event StatusChanged(string oldStatus, string newStatus);
mapping(address => uint256) public balances;
function transfer(address to, uint256 amount) public {
require(balances[msg.sender] >= amount, "Insufficient balance");
balances[msg.sender] -= amount;
balances[to] += amount;
// Emit event (frontend can listen to this)
emit Transfer(msg.sender, to, amount);
}
function deposit() public payable {
balances[msg.sender] += msg.value;
// indexed parameters can be filtered in frontend
emit Deposit(msg.sender, msg.value, block.timestamp);
}
// Why use events?
// 1. Much cheaper than storage
// 2. Frontend can listen in real-time
// 3. Create permanent log records
// 4. ERC20/721 standards require events
}事件特性
- emit 触发事件
- indexed 参数可被过滤(最多3个)
- 比存储在 storage 便宜得多
- 前端通过 web3.js/ethers.js 监听
典型使用场景
- ERC20 Transfer/Approval 事件
- 所有权转移事件
- 状态变更通知
- 前端实时更新 UI
8. 错误处理
Solidity 提供三种错误处理方式。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract ErrorsDemo {
uint256 public balance;
// Custom errors (0.8.4+, more gas efficient)
error InsufficientBalance(uint256 requested, uint256 available);
error Unauthorized(address caller);
error InvalidAmount();
function withdraw(uint256 amount) public {
// Method 1: require (most common)
require(amount > 0, "Amount must be positive");
require(balance >= amount, "Insufficient balance");
balance -= amount;
}
function withdrawWithCustomError(uint256 amount) public {
// Method 2: custom error + revert (saves gas)
if (amount == 0) revert InvalidAmount();
if (balance < amount) {
revert InsufficientBalance(amount, balance);
}
balance -= amount;
}
function directRevert() public pure {
// Method 3: direct revert
revert("Something went wrong");
}
function assertExample(uint256 x) public pure returns (uint256) {
// Method 4: assert (internal errors only, consumes all gas)
// NOT recommended for user input validation
assert(x != 0);
return 100 / x;
}
}错误处理方法
require(condition, "message")- 条件检查,失败回滚并退还剩余 gasrevert("message")- 直接回滚assert(condition)- 内部错误检查,失败消耗所有 gas(不推荐)自定义 Error(0.8.4+)- 更省 gas-
自定义错误
使用 error 关键字定义,用 revert ErrorName() 触发,比字符串错误省 gas。
9. 继承与接口
Solidity 支持多重继承和接口。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// Parent contract
contract Animal {
string public name;
constructor(string memory _name) {
name = _name;
}
function eat() public virtual returns (string memory) {
return "eating";
}
}
// Child contract
contract Dog is Animal {
constructor(string memory _name) Animal(_name) {}
// Override parent function
function eat() public pure override returns (string memory) {
return "dog is eating";
}
function bark() public pure returns (string memory) {
return "woof!";
}
}
// Multiple inheritance
contract Owner {
address public owner;
constructor() { owner = msg.sender; }
}
contract Pet is Animal, Owner {
constructor(string memory _name) Animal(_name) Owner() {}
// Call parent function
function parentEat() public view returns (string memory) {
return super.eat();
}
}
// Interface
interface IERC20 {
function transfer(address to, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
}
// Abstract contract
abstract contract ERC20Base {
mapping(address => uint256) public balances;
// Unimplemented function
function mint(address to, uint256 amount) public virtual;
// Implemented function
function balanceOf(address account) public view returns (uint256) {
return balances[account];
}
}继承
- 使用 is 关键字继承
- 支持多重继承(逗号分隔)
- virtual - 父合约函数可被重写
- override - 子合约重写父函数
- super - 调用父合约函数
接口(Interface)
- 只声明函数签名,不实现
- 所有函数必须是 external
- 不能有状态变量和 constructor
- 用于定义标准(如 IERC20)
抽象合约(Abstract)
- 包含至少一个未实现的函数
- 不能被部署,只能被继承
- 用 abstract 关键字标记
10. 高级特性
一些进阶语法和最佳实践。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// Library
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
}
contract AdvancedDemo {
using SafeMath for uint256; // Attach library to type
uint256 public value;
// Use library function
function addValue(uint256 x) public {
value = value.add(x); // Instead of value + x
}
// Inline assembly (advanced, use with caution)
function getCodeSize(address _addr) public view returns (uint256 size) {
assembly {
size := extcodesize(_addr) // Get contract code size
}
}
// Reentrancy guard pattern
bool private locked;
modifier nonReentrant() {
require(!locked, "Reentrancy detected");
locked = true;
_;
locked = false;
}
function withdrawAll() public nonReentrant {
uint256 amount = address(this).balance;
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
}
}库(Library)
- 类似合约,但不能有状态变量
- 使用 using for 语法扩展类型
- 常见:SafeMath、Address、Strings
内联汇编(Assembly)
- 使用 assembly { ... } 编写 Yul 代码
- 直接操作 EVM,极致优化 gas
- 高风险,需谨慎使用
安全最佳实践
- 检查 - 效果 - 交互模式(避免重入)
- 使用 ReentrancyGuard
- 避免使用 tx.origin(用 msg.sender)
- 整数溢出检查(0.8.0+ 自动)
- 合理使用 require 而非 assert
11. 学习资源
精选的 Solidity 学习资料和工具。
官方文档
Solidity 官方文档 ↗
最权威的参考资料,涵盖所有语法细节
Solidity by Example ↗
通过代码示例学习,简洁明了(强烈推荐)
交互式教程
进阶资源
OpenZeppelin Contracts ↗
经过审计的智能合约库(ERC20/721/1155 等)
Ethereum.org Developers ↗
以太坊开发者文档,涵盖生态全貌
WTF Academy ↗
中文 Solidity 教程,内容详实
开发工具
12. 实战项目路线图
按难度从低到高的实战项目建议,每个项目都能巩固特定的 Solidity 技能。
初级(1~2天能写完)
ERC-20 Token
⭐ 1天标准代币合约
Extensions
- 添加 mint/burn 功能
- 添加 pause 暂停机制
- 实现代币时间锁
ERC-721 NFT
⭐⭐ 1-2天非同质化代币(NFT)
Extensions
- 白名单 mint
- 荷兰拍卖
- 版税机制
多签钱包 (MultiSig Wallet)
⭐⭐ 2天N 个人签名才能转账
Extensions
- 每日限额
- 交易队列
- 紧急暂停
中级(3~7天)
AMM DEX(类 Uniswap V2)
⭐⭐⭐ 5-7天恒定乘积做市商
Features
- 添加/移除流动性
- 手续费分配
- 价格计算
- 滑点保护
💡 综合性强,推荐!涵盖 ERC-20 交互、数学计算、手续费机制
借贷协议(类 Aave 简化版)
⭐⭐⭐ 5-7天存款生息 + 抵押借贷
Features
- 存款/取款
- 借款/还款
- 清算
- Chainlink 喂价
💡 涉及复杂的利率计算和风险管理
Staking 合约
⭐⭐ 3-4天质押代币赚收益
Features
- 质押/解押
- 领取奖励
- 复利
- 提前解锁惩罚
💡 常见 DeFi 组件,适合练习数学计算
Vesting 合约
⭐⭐ 3天代币线性解锁
Features
- 线性释放
- 阶梯释放
- 可撤销/不可撤销
💡 适合模拟员工期权、项目方锁仓
高级(2周+)
Uniswap V3 集中流动性
⭐⭐⭐⭐⭐ 2-3周价格区间流动性
Features
- 集中流动性
- 多价格区间
- 手续费等级
- NFT LP
⚠️ 数学复杂度极高,需要深入理解定点数和价格计算
跨链桥
⭐⭐⭐⭐ 2周资产跨链转移
Features
- 双链部署
- 事件监听
- 默克尔证明
- 挑战期
⚠️ 需要理解跨链通信原理和安全风险
Perpetual(永续合约)
⭐⭐⭐⭐⭐ 3-4周去中心化衍生品交易
Features
- 开仓/平仓
- 杠杆
- 资金费率
- 自动清算
⚠️ 难度极高,类似 Hyperliquid 的核心协议
建议学习路径
ERC-20已完成 ✓
掌握基础语法和代币标准
MultiSig Wallet推荐
练习权限控制和 mapping 嵌套
AMM DEX V2核心
理解 DeFi 核心逻辑(推荐从 SimpleSwap 扩展)
借贷协议进阶
学习预言机集成和清算机制
跨链桥 or V3高级
挑战复杂的跨链或数学问题
💡 下一步建议
你现在 Sepolia 上的 SimpleSwap 就是 AMM 的雏形,直接在那个基础上扩展成完整的 Uniswap V2 是最顺的路线。可以逐步添加:
- 流动性池管理(addLiquidity / removeLiquidity)
- LP Token 铸造和销毁
- 手续费累积和分配(0.3% 给 LP)
- 价格预言机(TWAP)
- 滑点保护和截止时间检查