# Solidity极简入门: 30. Try Catch **Published by:** [0xAA](https://paragraph.com/@wtfacademy/) **Published on:** 2022-05-25 **URL:** https://paragraph.com/@wtfacademy/solidity-30-try-catch ## Content 我最近在重新学solidity,巩固一下细节,也写一个“Solidity极简入门”,供小白们使用(编程大佬可以另找教程),每周更新1-3讲。 欢迎关注我的推特:@0xAA_Science WTF技术社群discord,内有加微信群方法:链接 所有代码和教程开源在github(1024个star发课程认证,2048个star发社群NFT): github.com/AmazingAng/WTFSoliditytry-catch是现代编程语言几乎都有的处理异常的一种标准方式,solidity0.6版本也添加了它。这一讲,我们将介绍如何利用try-catch处理智能合约中的异常。try-catch在solidity中,try-catch只能被用于external函数或创建合约时constructor(被视为external函数)的调用。基本语法如下: try externalContract.f() { // call成功的情况下 运行一些代码 } catch { // call失败的情况下 运行一些代码 } 其中externalContract.f()时某个外部合约的函数调用,try模块在调用成功的情况下运行,而catch模块则在调用失败时运行。 如果调用的函数有返回值,那么必须在try之后声明returns(returnType val),并且在try模块中可以使用返回的变量;如果时创建合约,那么返回值是新创建的合约变量。 try externalContract.f() returns(returnType val){ // call成功的情况下 运行一些代码 } catch { // call失败的情况下 运行一些代码 } 另外,catch模块支持捕获特殊的异常原因: try externalContract.f() returns(returnType){ // call成功的情况下 运行一些代码 } catch Error(string memory reason) { // 捕获失败的 revert() 和 require() } catch (bytes memory reason) { // 捕获失败的 assert() } try-catch实战OnlyEven我们创建一个外部合约OnlyEven,并使用try-catch来处理异常:contract OnlyEven{ constructor(uint a){ require(a != 0, "invalid number"); assert(a != 1); } function onlyEven(uint256 b) external pure returns(bool success){ // 输入奇数时revert require(b % 2 == 0, "Ups! Reverting"); success = true; } } OnlyEven合约包含一个构造函数和一个onlyEven函数。构造函数有一个参数a,当a=0时,require会抛出异常;当a=1时,assert会抛出异常;其他情况均正常。onlyEven函数有一个参数b,当b为奇数时,require会抛出异常。处理外部函数调用异常首先,在TryCatch合约中定义一些事件和状态变量: // 成功event event SuccessEvent(); // 失败event event CatchEvent(string message); event CatchByte(bytes data); // 声明OnlyEven合约变量 OnlyEven even; constructor() { even = new OnlyEven(2); } SuccessEvent是调用成功会释放的事件,而CatchEvent和CatchByte是抛出异常时会释放的事件,分别对应require/revert和assert异常的情况。even是个OnlyEven合约类型的状态变量。 然后我们在execute函数中使用try-catch处理调用外部函数onlyEven中的异常: // 在external call中使用try-catch function execute(uint amount) external returns (bool success) { try even.onlyEven(amount) returns(bool _success){ // call成功的情况下 emit SuccessEvent(); return _success; } catch Error(string memory reason){ // call不成功的情况下 emit CatchEvent(reason); } } 当运行execute(0)的时候,因为0为偶数,没有异常抛出,调用成功并释放SuccessEvent事件;当运行execute(1)的时候,因为1为偶数,异常抛出,调用失败并释放CatchEvent事件。处理合约创建异常这里,我们利用try-catch来处理合约创建时的异常。只需要把try模块改写为OnlyEven合约的创建就行: // 在创建新合约中使用try-catch (合约创建被视为external call) // executeNew(0)会失败并释放`CatchEvent` // executeNew(1)会失败并释放`CatchByte` // executeNew(2)会成功并释放`SuccessEvent` function executeNew(uint a) external returns (bool success) { try new OnlyEven(a) returns(OnlyEven _even){ // call成功的情况下 emit SuccessEvent(); success = _even.onlyEven(a); } catch Error(string memory reason) { // catch失败的 revert() 和 require() emit CatchEvent(reason); } catch (bytes memory reason) { // catch失败的 assert() emit CatchByte(reason); } } 大家可以运行一下executeNew(0),executeNew(1),executeNew(2),看看会有什么不同。总结在这一讲,我们介绍了如何使用try-catch来处理智能合约运行中的异常:只能用于外部合约调用和合约创建。如果try执行成功,返回变量必须声明,并且与返回的变量类型相同。 ## Publication Information - [0xAA](https://paragraph.com/@wtfacademy/): Publication homepage - [All Posts](https://paragraph.com/@wtfacademy/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@wtfacademy): Subscribe to updates - [Twitter](https://twitter.com/0xAA_Science): Follow on Twitter