第六章 | Solidity 函数与可见性修饰符全面讲解
📚 第六章 | Solidity 函数与可见性修饰符全面讲解
——写对函数,合约安全又高效!
✅ 本章导读
智能合约中,函数 是一切交互的入口。
不管你是发币、发 NFT、做 DeFi,所有的链上操作都要通过函数来完成。
而 Solidity 的函数有非常细的权限管理和执行逻辑,如果不懂这些规则,你可能会:
- 把外部接口暴露成公开函数 → 被黑客利用
 - 没理解 
view和pure,导致 Gas 浪费 - 不小心写出可重入函数,引发安全漏洞
 fallback和receive函数没写好,收不到 ETH- 弄错 
this.内外部调用,Gas 费用直接翻倍 
这一章,从基础写法到进阶用法,从安全优化到实战应用,一步步来。
✅ 本章你将掌握
- Solidity 函数基础用法
 - 可见性修饰符(public / private / internal / external)
 - 状态修饰符(pure / view / payable)
 - 特殊函数(constructor / fallback / receive)
 - 函数重载
 - 实战案例
 - 最佳实践和常见坑
 
1️⃣ Solidity 函数基础
Solidity 的函数就是对外暴露的接口,跟区块链用户交互、控制资产转移、调用合约的关键。
✅ 函数基本结构
function 函数名(参数) 可见性 状态修饰符 返回值类型 { // 函数逻辑}
示例
function add(uint a, uint b) public pure returns (uint) { return a + b;}
2️⃣ 函数的可见性修饰符(Visibility)
publicprivateinternalexternal函数() 调用(需 this.)✅ public
任何人都能调,合约对外接口默认选择
function getBalance() public view returns (uint) { return address(this).balance;}
✅ private
只能本合约内部访问,不能被继承合约访问
function _calcFee(uint amount) private pure returns (uint) { return amount * 2 / 100;}
✅ internal
本合约 + 子合约能访问,继承模式下常用
function _mint(address to, uint amount) internal { balances[to] += amount;}
✅ external
只能外部访问,不能内部直接调用(但可以用 this.函数())
function deposit() external payable { balances[msg.sender] += msg.value;}
⚠️ 常见坑
external比public更省 Gas(只读参数不复制)external不支持内部函数直接调,除非this.,但这样调用贵!- 大多数项目 
external用于对外交易入口、跨合约调用接口 
3️⃣ 状态修饰符(State Mutability)
pureviewpayable✅ pure
- 无链上状态交互
 - 仅纯运算
 
function add(uint a, uint b) public pure returns (uint) { return a + b;}
✅ view
- 可读链上状态
 - 不改变状态
 
function balanceOf(address user) public view returns (uint) { return balances[user];}
✅ payable
- 函数可以收 ETH
 - 不加 
payable,用户打钱也进不来 
function deposit() public payable { balances[msg.sender] += msg.value;}
⚠️ 常见坑
- 收 ETH 必须 
payable,不然交易直接失败 payable通常配合receive()或fallback()- 推荐给 
constructor加payable,支持初始化打款 
4️⃣ 特殊函数(constructor / receive / fallback)
👉 constructor(构造函数)
- 合约部署时自动执行一次
 - 一般用于初始化 owner、配置参数
 
constructor(uint _initSupply) { owner = msg.sender; totalSupply = _initSupply;}
⚠️ 注意
- 只能执行一次
 - 不可被外部再次调用
 payable constructor支持部署时转 ETH
👉 receive
- 专门收 ETH,必须 
payable - 无参数、无返回值
 
receive() external payable { emit Received(msg.sender, msg.value);}
⚠️ 规则
- 用户 
transfer()或send()时自动触发 - 优先级高于 
fallback - 不写 
receive(),收不到直接打进来的 ETH 
👉 fallback
- 处理未定义函数调用
 - 可以 
payable接收 ETH 
fallback() external payable { emit Fallback(msg.sender, msg.value);}
场景
- 升级代理合约
 - 实现 
call路由 - 收未知函数调用
 - 捕获错误转账
 
5️⃣ 函数重载(Overloading)
Solidity 支持多个重名函数,只要参数不同即可。
function register(string memory name) public { ... }function register(string memory name, uint age) public { ... }
⚠️ 注意
- 只能在编译时决定,前端调用 ABI 必须明确区分
 - 建议使用函数签名:
functionName(type1,type2) 
6️⃣ 实战案例 | 钱包合约函数设计
✅ 合约目标
- 用户打钱到合约
 - owner 提现 ETH
 - 记录充值、提现事件
 
✅ 合约代码
// SPDX-License-Identifier: MITpragma solidity ^0.8.19;contract SimpleWallet { address public owner; event Deposit(address indexed user, uint amount); event Withdraw(address indexed user, uint amount); error NotOwner(address caller); constructor() payable { owner = msg.sender; } receive() external payable { emit Deposit(msg.sender, msg.value); } fallback() external payable { emit Deposit(msg.sender, msg.value); } function deposit() external payable { emit Deposit(msg.sender, msg.value); } function withdraw(uint amount) external { if (msg.sender != owner) { revert NotOwner(msg.sender); } (bool success, ) = payable(owner).call{value: amount}(\"\"); require(success, \"Withdraw failed\"); emit Withdraw(owner, amount); } function balance() external view returns (uint) { return address(this).balance; }}
✅ 讲解
receive()/fallback()处理所有转账入口withdraw()权限控制只允许 ownerexternal+view节省 Gas- 自定义错误 
NotOwner节省报错 Gas call{value:}安全转账,避免transfer限制constructor payable支持部署时初始化充值
7️⃣ 最佳实践 & 常见坑
✅ 最佳实践
- 外部调用用 
external,内部调用public - 纯计算函数用 
pure,读状态view payable明确收 ETH 的函数receive()+fallback()双保险收 ETH- 错误处理推荐用 
revert+ 自定义错误 onlyOwner权限控制必须有- 事件必须 emit,前端数据靠事件同步
 
⚠️ 常见坑
- 函数没加 
payable,导致 ETH 打不进来 fallback()没写payable,ETH 被拒绝external函数内部调用爆 Gasconstructor内部初始化没传值- 函数权限设计不严密 → 被黑客攻击!
 
✅ 小结
这一章我们系统讲解了 Solidity 函数:
✔️ 函数的声明与结构
✔️ 可见性修饰符
✔️ 状态修饰符
✔️ 特殊函数(constructor、receive、fallback)
✔️ 函数重载
✔️ 实战设计安全函数体系
🎯 课后挑战
- 编写一个 “白名单” DApp
 
- 注册白名单用户
 - owner 批量添加/删除白名单
 - 查询白名单状态
 - 事件触发白名单变化
 - fallback 接收 ETH 并记录日志
 
- 用 Hardhat 部署本地测试
 - 写自动化测试覆盖各种调用
 
✅ 下一章预告|第七章
👉 合约继承与接口
🚀 多合约协作开发
🚀 继承重写 / 函数重载 / 抽象合约
🚀 接口 interface 设计模式
🚀 实战 DAO / NFT 工厂合约
🚀 多继承冲突与钻石标准


