try-catch
是现代编程语言几乎都有的处理异常的一种标准方式,solidity 0.6之后的版本也添加了这一功能。相比于solidity中经典的
assert
、
require
和
revert
,
try-catch
在处理函数调用中发生的失败之后,并不需要回滚整个交易。接下来就介绍一下这一语句。
try-catch
在solidity中,try-catch
只能被用于external函数或创建合约时constructor(被视为external函数)的调用。例如:
try externalContract.f() returns(returnType val) {
// call成功的情况下 运行一些代码
} catch {
// call失败的情况下 运行一些代码
}
其中externalContract.f()
代表外部函数,return表示该外部函数的返回值(没有可以省略),如果调用成功的话则执行try{}里面的语句,失败的话则执行catch{}里面的语句
如果想要将其用于合约内部的函数,则需要使用this
方法来指向本合约(不能在构造函数中使用),例如:
try this.f() {
// call成功的情况下 运行一些代码
} catch {
// call失败的情况下 运行一些代码
}
另外,try-catch
还支持捕获错误原因,例如:
try externalContract.f() returns(returnType){
// call成功的情况下 运行一些代码
} catch Error(string memory err) {
console.log(err);
}
实例
在下面的例子中,我们想要找到tokenId在 0 − 100 0-100 0−100范围内,哪些NFT没有被铸造:
代码
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "hardhat/console.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
interface NFTContract {
function ownerOf(uint256 _tokenId) external view returns (address);
}
contract tryCatch {
uint256[] a;
function m(address con) public returns (uint256[] memory){
for (uint256 i = 0; i < 10; i++) {
try NFTContract(con).ownerOf(i) {
console.log(i);
}
catch {
a.push(i);
}
}
return a;
}
}
其中address con
代表所观察NFT的合约地址,ownerOf函数功能是找到给定tokenId的持有者,如果tokenId不存在,则报错。
测试
将上述代码复制到remix中,并部署合约
事先部署一个简单的NFT合约,并mint了三个NFT,然后调用上述合约中的m函数,可以看到,当函数执行到已经mint了的tokenId 的时候,就会执行console.log,执行到未mint的tokenId的时候,就会向数组a中push该tokenId,最终输出。
附 上述NFT代码
//SPDX-License-Identifier:MIT
pragma solidity ^0.8.17;
import '@openzeppelin/contracts/token/ERC721/ERC721.sol';
// 继承ERC721, Ownable
contract Simple721Contract is ERC721 {
uint256 public totalSupply;
constructor() ERC721('Simple Erc-721 NFT', 'SMPL721') {
}
function mint() external payable {
totalSupply++;
uint256 tokenId = totalSupply;
_safeMint(msg.sender, tokenId);
}
}