ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Solidity

2021-05-08 19:04:02  阅读:775  来源: 互联网

标签:function return Solidity returns uint memory public


起因是Xenc师傅给我截了张图,我日 居然看不懂 ,一搜才知道,之前学的版本有些老了.. 这次学下新一点的记录下

HelloWorld

pragma solidity ^0.6.0;     // version

contract One{
    // 状态变量
    string name;
    
    function setName() public{  // 必须要加权限修饰符了
        name = "Muxue";
    }
    
    // view修饰的函数 表示访问状态变量, 但是不会修改, 不会消耗任何资源
    function getName() public view returns(string memory){  // 返回字符串类型也需要加memory了
        return name;
    }
    
    // pure修饰的函数 不不修饰也不读取状态变量 不会消耗任何资源
    function pureTest() public pure returns(string memory){
        return "test";
    }

}

变量 常量 标识符 关键字

变量

type name = value;

标识符

需要命名的地方都是标识符
标识符命名规则

1. 字符, 数字, _, $组成
2. 不能以数字开头
3. 区分大小写

数据类型

基本类型

  1. 布尔(bool)
  2. 整形(int / uint)
  3. 地址(address)
  4. 定长字节数组
  5. 定长浮点(fixed / ufixed)
  6. 枚举类型(enum)
  7. 函数类型(function)

引用类型

  1. 数组(array) {不定长字节数组, 字符串}
  2. 结构体(struct)
  3. 映射(mapping)

区别

值类型一般都是值拷贝传递,但引用类型 有些是地址传递

数组

全局数组

全局的是storage
Array
几种声明 初始化方式

pragma solidity ^0.6.0;

contract ArrayTest{
    uint[4] arr1;    // 固定数组的声明
    uint[] arr2;    //  动态长度数组的声明
    
    // 声明并初始化
    uint[2] arr3 = [1,2];
    uint[] arr4 = [1,4,12,4,2];
    
    // 使用new
    uint[] public arr5 =  new uint[](3);
} 

length和push pop的讲解

length: 长度 修改length 可改变动态长度数组的长度,但是0.6.0以上的版本都不能使用length修改数组长度
push:固定数组不能用 动态数组storage可以用 memory不能用
pop: 把push进来的数据 再顶出去

pragma solidity ^0.6.0;

contract ArrayTest{
    uint[] arr4 = [1,4,12,4,2];
    
    // 使用new
    uint[] public arr5 =  new uint[](3);
	
    function push() public{
        arr5.push(1);
    }
    
    // 尝试使用修改length
    function changeLength() public{
        // arr4.length = 12; // browser/Array/1.sol:19:9: TypeError: Member "length" is read-only and cannot be used to resize arrays. arr4.length = 12; // ^---------^
    }
    
    
    function Get() view public returns(uint[] memory){
        return arr5;
    }
    
    function pop() public{
        arr5.pop();     // 把push进来的再推出去
    }
    
}

局部数组

局部的是memory
注意的一点是 新版本的 局部的都要加memory,包括返回数组 返回值那里

pragma solidity ^0.6.0;

contract ArrayTest{
    
    function test() public returns(uint[] memory){
        uint[] memory arr8 = new uint[](3);    // 使用new方法创建局部数组
        arr8[0] = 1;
        return arr8;   
    }
    
}

数据存储位置

storage:是存在区块链 上的,全局变量

哪些数组类型可以使用storage
- 数组
- 结构体
- 映射

memory:是存在内存上的,函数内的 局部的变量
:值类型的局部变量存储在这里
calldata:当函数为外部函数(external),如果此函数的参数(非返回参数),则参数要求必须用calldata,(教程里是这样说的,但是我用memory也没报错)
image

对于存储型的数组(storage), 可以放任意的元素类型
对于内存性的数组(memory), 元素不可以是映射类型mapping

storage和memory的相互转换

pragma solidity ^0.6.0;

contract testFunc{
        
    uint[] public a1Storage = [1,2,3];
    
    function Geta1() public view returns(uint[] memory){
        return a1Storage;
    }
    // sotrage -> memory    值传递 不会修改storage的值
    function storageTomemory() public view{
        uint[] memory b = a1Storage;   // storage 赋值给 memory
        b[0] = 100;
    }
    
    // memory -> storage    值传递
    function memoryTostorage() public{
        uint8[4] memory c = [2,4,1,5];
        a1Storage = c;
        c[0] = 255;
    }
    
    // sotrage -> storage    引用传递 修改一个 原数据也会修改数据
    function storageTostorage() public{
        uint[] storage m = a1Storage;
        m[1] = 123;
    }
    
    // memory -> memory      引用传递
    function memoryTomemory() public view returns(uint8[3] memory){
        uint8[3] memory a = [1,2,3];
        uint8[3] memory b = a;
        b[1] = 12;
        return a;
    }
    
}

简单来说两个相同的都是引用传递,不同的都是值传递

字节数组

也分为

  • 变长字节数组
  • 定长字节数组
    bytes : 变成字节数组
    bytes+num:后面跟数字的是定长字节数组
pragma solidity ^0.6.0;
contract Test{
    
    bytes b1;   // 变长字节数组 bytes里是以16进制存储值的
    bytes b2 = "abc\x22\x25";   // \x后面就代表是十六进制的值
    bytes b3 = "ce\u8bd5";
    
    function Get() public view returns( bytes memory){
        return b3;
    }
    
    bytes4 bt = 0x74657374;     // 定长字节数组
    
}

定长字节数组转变长字节数组

pragma solidity ^0.6.0;
contract Test{
    
    bytes4 bt = 0x74657374;     // 定长字节数组
    
    // 把定长字节数组转换成变长字节数组
    function To() public view returns(bytes memory){
        bytes memory temp = new bytes(bt.length);
        for(uint i=0;i<bt.length;i++){
            temp[i] = bt[i];
        }
        return temp;
    }
}

string

string没啥好说了吧 我擦..
字节转字符串

pragma solidity ^0.6.0;
contract Test{
    
    bytes public name = "慕雪";
    function EchoName() public view returns(string memory){
        return string(name);
    }
    
}

Solidity交易和内置对象

提到交易不得不提Gas了哈,也就是燃料也叫手续费
Gas又分为两个:

  • gas price 每个gas的价格
  • gas limit 限制gas的最大值

需要给矿工预付的gas = gas price * gas limit

消息:不修改合约状态,如带有pure,view等关键字的

账户和地址

分为外部账户合约账户, 外部账户地址, 外部合约地址

也就是外部账户和外部合约都各有地址

外部账户:我们钱包的一个用户 给你一个地址 就是一个外部账户
image
合约账户:我们部署一个合约 都会给我们一个地址
image

地址
address

  • 20个字节,160位
  • 值类型

address payable
0.5.0以后出的
只能使用它来进行转账

属性

  • balance

函数
专门用来做交易的

  • transfer
  • send

不会提示错误

demo code

pragma solidity ^0.6.0;

contract Test{
    function echoAddress() public view returns(uint){
        address _address = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
        return uint(_address);
    }
    
    function getBalance(address _account) public view returns(uint){
        return _account.balance;
        // return address(this).balance; 返回当前合约账户余额
        // this是指当前合约账户
    }
    
    function getThis() public view returns(address){
        return address(this);
    }
    
    function testTransfer() public payable{
        address(this).transfer(msg.value);  // 前面是要给哪个地址转账的地址
    }
    
    function testTransfer2() public payable{
        address payable _address = address(this);   // 转账必须加payable
        _address.transfer(1 ether);     // 虽然这里写1了 但是我们还是需要在value那里设置1 ether
    }
	
	function testSend() public payable{
        address payable _address = address(this);
        _address.send(1 ether);
    }
    
    fallback() payable external{    // 回退函数
        
    }
    receive() payable external{
        
    }
}

transfersend的区别:

transfer假如value和设置的值不同 会报错。而send不会,但会返回一个false,但是错误了 还是会扣钱

Solidity单位和全局变量

具体可以看
https://solidity-cn.readthedocs.io/zh/develop/units-and-global-variables.html?highlight=全局#id3

区块链和交易属性

pragma solidity ^0.6.0;

contract One{
    /*
        block.blockhash(uint blockNumber) returns (bytes32):指定区块的区块哈希——仅可用于最新的 256 个区块且不包括当前区块;而 blocks 从 0.4.22 版本开始已经不推荐使用,
        由 blockhash(uint blockNumber) 代替
        block.number (uint): 当前区块号
        msg.data (bytes): 完整的 calldata
        msg.gas (uint): 剩余 gas - 自 0.4.21 版本开始已经不推荐使用,由 gesleft() 代替
        msg.sig (bytes4): calldata 的前 4 字节(也就是函数标识符)
        msg.value (uint): 随消息发送的 wei 的数量
        tx.gasprice (uint): 交易的 gas 价格
        tx.origin (address): 交易发起者(完全的调用链)
    */
    
    function getBlockHash() public view returns(bytes32){
        return blockhash(block.number-1);     // block.number 当前区块号,得-1 要不然获取不到hash
    }
    
    // block.coinbase (address): 挖出当前区块的矿工地址
    function getBlockCoinbase() public view returns(address){
        return block.coinbase;
    }
    
    //  block.difficulty (uint): 当前区块难度
    function getBlockDifficulty() public view returns(uint){
        return block.difficulty;
    }
    
    // block.gaslimit (uint): 当前区块 gas 限额
    function getBlockLimit() public view returns(uint){
        return block.gaslimit;
    }
    
    //  block.timestamp (uint): 自 unix epoch 起始当前区块以秒计的时间戳
    function getBlockTimestamp() public view returns(uint){
        return block.timestamp;
    }
    
    // gasleft() returns (uint256):剩余的 gas
    function getGasleft() public view returns(uint){
        return gasleft();
    }
    
    // now (uint): 目前区块时间戳(block.timestamp)
    function getTime() public view returns(uint){
        return now;
    }
    
    // msg.sender (address): 消息发送者(当前调用)
    function GetMsgsender() public view returns(address){
        return msg.sender;
    }
    
}

image

错误处理

最常用的应该就是require了吧

pragma solidity ^0.6.0;

contract Two{
    uint public money;
    address master;
    constructor() public{       // 构造函数
        master = msg.sender;
    }
    
    function changeMoney() public {
        require(msg.sender ==  master); // 如果不是 就直接报错了 不会往下面走
        money += 5000;
    }
}

函数

也就是function,已经非常熟悉了

可见性

  • public:内部 外部都可调用,状态变量和函数都可以用
  • private:私有的 只有内部可以调用,状态变量和函数都可以用
  • internal:只有内部可以调用,状态变量和函数都可以用
  • external:只有外部可以调用,只有函数可以用
    image
    image

可以明显的看出 被privateinternal修饰的函数 外部不可以调用

external修饰的内部不可以调用
如要调用可以加一个this.

function test3() public view returns(uint) {
	return this.testExternal();
}

调用方式

  • external:外部的 也就是外部点击函数名称那种方式
  • internal:内部的 就是一个合约方法调用另一个方法呗

可变性 可修改性

  • pure:不用状态变量的时候
  • view:需要用到状态变量
  • payable:需要付款的时候
  • constant:和view一样的,0.5.0以后舍弃了

返回值

pragma solidity ^0.6.0;

contract Two{
    // 返回多个参数
    function test1() public pure returns(uint a,uint b){
        return (2,4);
    }
    
    // 写参数名字
    function test2() public pure returns(uint sum){
        sum = 1+2;  // 不需要加类型 因为上面我们定义了
        // 不用reutrn 要是return,以return的值为结果
    }
}

get

public修饰的变量,系统默认写了一个同名的函数,用来获取值,0.5.0以上的版本 不支持重写了
image

修改器 modifier

作用:可以修改函数的行为,控制函数的逻辑,代码重用

pragma solidity ^0.6.0;

contract TestModifier{
    
    uint public a;
    
    // create modifier
    modifier myModifier(){
        a=1;
        _;  // 函数会到这
        a=10;
    }
    
    // call modifier
    function callModifier() public  myModifier{
        a=9;       // 最终结果为10
    }
    
}

带参数的modifier

来个demo看看modifier的强大之处

pragma solidity ^0.6.0;

contract Two{
    uint public level;
    string public name;
    string public sex;
    
    modifier levelRequire(uint _level) {
        require(level>=_level);
        _;
    }
    
    function setLevel(uint _num) public{
        level = _num;
    }
    
    function setName() public levelRequire(5){  // 相当于level需要大于或者等于五级才可以调用此方法
        name = "Muxue";		// 如果modifier的_;后面还有 会在当前代码后面执行
    }
    
    function setSex() public  levelRequire(7){
        sex = "male";
    }
    
}

多重modifier的执行顺序

这个是有点东西的

contract Three{
    uint public a = 1;
    
    modifier Test1{
        a = 2;  // 执行顺序1
        _;      // 把Test2带进来
        a = 3;  // 执行顺序5    也就是最后一个
    }
    
    modifier Test2{
        a = 4;  // 执行顺序2
        _;      // 把test函数带进来
        a = 5;  // 执行顺序4
    }
    
    function test() public Test1 Test2{
        a = 6;  // 执行顺序3
        // a的结果为3
    }
}

如果不信的 可以debug一步步的调着看

image

合约

构造函数

  • 合约创建时自动调用,且只调用一次。每个合约只能有一个构造函数
  • 构造函数一般是为状态变量初始化
  • constructor 关键字
  • 分为有参和无参
pragma solidity ^0.6.0;

contract TestNewContract{
    uint age;
    constructor(uint _age) public{
        age = _age;
    }    
}

封装性

  1. 函数合约

  2. 修饰符(访问修饰符)

    • public, private , internal, external

      • 状态变量:publicprivate, internal
      • 函数:publicprivate, internal, external

继承

  • is 关键字
pragma solidity ^0.6.0;

contract Father{
    
    address owner;
    string name;
    uint money = 100000000000000000000000;
    
    constructor() public{
        owner = msg.sender;
        name = "Muxue";
    }
    
    function changeName(string memory _name ) public{
        require(msg.sender == owner);
        name = _name;
    }
    
}

contract Son is Father{
    function getMoney() public view returns(uint){
        return money;   // 继承的父亲的
    }
}

父合约构造函数的传参

pragma solidity ^0.6.0;

contract Father{
    uint private age;
    constructor(uint _age) public{
        age = _age;
    }
}
    
contract Son is Father(46){ // 继承式
    
}
    // 这两种方法不能同时使用
contract Son2 is Father{
    constructor() Father(46) public{    // 修改风格式
        
    }
}

多态

重写父类方法和状态变量

得在父类方法上加上virtual关键字,子类重写的方法加上override方法

pragma solidity ^0.6.0;

contract A{
    function F() public pure virtual returns(string memory){ //  仅当函数被标记为 virtual 或在接口中定义 时,才可以覆盖  
        return "A";
    }
}

contract B is A{
    // 函数重写
    function F() public pure override returns(string memory){      // override 代表可重写    
        return "B";
    }
    // 函数重载
    function F(string memory _test) public pure returns(string memory){
            return _test;
        }
    
}

父类:virtual,子类:override
重写要保证,函数名,参数,返回值相同

重写状态变量
0.6.0后 不可再重写状态变量

super

pragma solidity ^0.6.0;

contract A{
    function F() public pure virtual returns(string memory){ //  仅当函数被标记为 virtual 或在接口中定义 时,才可以覆盖  
        return "A";
    }
    
    function eat() public pure virtual returns(string memory){
        return "rou";
    }
}

contract B is A{
    // 函数重写
    function F() public pure override returns(string memory){      // override 代表可重写    
        return "B";
    }
        // 函数重载
    function F(string memory _test) public pure returns(string memory){
            return _test;
    }
    
    function eat() public pure override returns(string memory){
        return "yu";
    }
       
    function test() public view returns(string memory){
        // return eat();   // 调用的是自己重写的那个方法
        return super.eat(); // 调用父类eat方法
    }         
    
}

想要调用父类的,也可以用 父类名.方法名
super是内部调用

多重继承 重写父类方法

pragma solidity ^0.6.0;

contract Father{
    function getMoney() public pure virtual returns(uint ){
        return 10000;
    }
}

contract Mother{
    function getMoney() public pure virtual returns(uint ){
        return 8000;
    }
}

contract Son is Father,Mother{
    function getMoney() public pure override(Father,Mother) returns(uint){		// 处理重名函数
        return 18000;
    }
}

这个在我编译时,一直在报错,但是我还不知道哪错了,我用0.8.4编译一次之后,没问题。最后再换回0.6的版本,照样可以编译成功

抽象合约

抽象合约

  • 关键字:abstract
  • 抽象合约中,可以有抽象函数,非抽象函数
  • 抽象函数 不需要实现函数体
  • 抽象合约不能实例化

作用:起到约束,约束继承的抽象合约的子合约,必须重写抽象函数

pragma solidity ^0.6.0;

abstract contract Father{   // 抽象合约		关键字 abstract
    function eat() public pure virtual; // 抽象函数
}

contract Son is Father{
    // 必须重写函数
    function eat() public pure override{
        
    }
}

接口

  • 关键字interface
  • 接口中所有的函数都是抽象函数,所有可以省略virtual关键字
  • 接口函数的修饰符必须使用external
  • 其余限制:不能继承其他合约或接口,不能定义构造函数,不能定义状态变量,不能定义结构体
interface Father{   // 接口
    function eat() external pure;    // 没有{}
}

contract Son is Father{
    function eat() public pure override{    // 重写eat方法
        
    }
}

作用

  • 代码重要性
  • 将多个合约重复的代码提取到一个库中
  • 不需要继承 节省gas

关键字及特性

libray

  • 库中的函数不能修改状态变量
  • 库不可以被销毁
  • 不能定义状态变量
  • 不可以继承其他元素,也不能被继承
  • 库不能接受以太币

使用

有两种方式
库名.方法名

pragma solidity ^0.6.0;

library Search{ // 库定义
        function indexOf(uint[] storage _data,uint _value) public view returns(uint){
        for(uint i=0;i<_data.length;i++){
            if(_data[i] == _value){
                return i;
            }
        }
        return uint(-1);
    }
}

contract TestLibray{    // 第一种
    uint[] data;
    
    constructor() public{
        data.push(1);
        data.push(2);
        data.push(3);
        data.push(4);
    }
    
    // 调用库函数
    function indexof(uint _value) public view returns(uint){
        return Search.indexOf(data,_value);
    }
}

using 库名 for 状态变量

pragma solidity ^0.6.0;

library Search{ // 库定义
        function indexOf(uint[] storage self,uint _value) public view returns(uint){    // self也就是传过来的那个类型
        for(uint i=0;i<self.length;i++){
            if(self[i] == _value){
                return i;
            }
        }
        return uint(-1);
    }
}

contract TestUsingFor{

    using Search for uint[];    // 把search这个库绑定为uint[]类型
    uint[] data;
    
    constructor() public{
        data.push(1);
        data.push(2);
        data.push(3);
        data.push(4);
    }
    
    // 调用库函数
    function indexof(uint _value) public view returns(uint){
        return data.indexOf(_value);    // 会自动把data传给第一个参数
    }
}

合约销毁

合约生命周期

  1. 合约创建(new、sdk)
  2. 合约操作、使用(调用函数实现功能)
  3. 合约销毁(区块链上 关于合约的存储和代码都会被删除)
pragma solidity ^0.6.0;

library Search{ // 库定义
        function indexOf(uint[] storage self,uint _value) public view returns(uint){    // self也就是传过来的那个类型
        for(uint i=0;i<self.length;i++){
            if(self[i] == _value){
                return i;
            }
        }
        return uint(-1);
    }
}

contract TestUsingFor{

    using Search for uint[];    // 把search这个库绑定为uint[]类型
    uint[] data;
    address owner;
    
    constructor() public{
        owner = msg.sender;
        data.push(1);
        data.push(2);
        data.push(3);
        data.push(4);
    }
    
    modifier onlyOwner() {
        require(owner == msg.sender);
        _;
    }
    
    // 调用库函数
    function indexof(uint _value) public view returns(uint){
        return data.indexOf(_value);    // 会自动把data传给第一个参数
    }
    
    function kill() public onlyOwner{
        selfdestruct(msg.sender);   // 销毁合约
    }
    
}

映射

引用数据类型

关键字及特性

  1. mapping
  2. 存储一对数据,以key-value形式的
  3. key的数据类型是有要求的:动态数组,枚举,structmapping都不可以;value基本上都可以
  4. mapping不能作为参数使用
pragma solidity ^0.6.0;

contract TestMapping{
    mapping(uint=>string) public uintMapping; // key:uint value:string
    mapping(address=>uint) public addressMapping;
    mapping(string=>mapping(uint=>address)) public stringMapping;
    
    constructor() public{
        uintMapping[1] = "test";
        addressMapping[0x5B38Da6a701c568545dCfcB03FcB875f56beddC4] = 1;
        addressMapping[0x17F6AD8Ef982297579C203069C1DbfFE4348c372] = 2;
        stringMapping["Muxue"][1] = 0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB; // 复杂的是[key][key] = value;
        
    }
}

结构体

引用数据类型

关键字及特性

  1. 关键字struct
  2. 大部分类型都可以,但是不可以包含自己本身
  3. 结构体作为函数的返回值类型使用时
    • 结构体中有mapping类型,函数只能使用internal,private
    • 结构体中没有mapping类型,需要添加pragma experimental ABIEncoderV2;
contract TestStruct{
    struct People{
        uint id;
        string name;
        mapping(string=>uint) grade;
        // People test;
    }
    
    People public pp;
    
    constructor() public{
        // People memory ppt = People(1,"Muxue");  // mapping类型不能直接赋值,因为是storage的
        People memory ppt = People({name:"Muxue",id:1});
        pp = ppt;
        pp.grade["level"] = 1;
    }
    
}

枚举

  1. 作用:增强代码的可读性
  2. 基本数据类型
  3. 关键字:enum
  4. 书写时不能有;
  5. 不能有""
  6. 不能有中文
  7. 结果可以转为uint
contract TestEnum{
    enum Sex{Man,Woman}
    
    function useEnum() public pure returns(Sex){
        return Sex.Man;
    }
    
    function useenum() public pure returns(uint){
        return uint(Sex.Woman);
    }
}

事件与日志

  1. 合约中不能直接访问日志中的内容,可以通过sdk的方式进行交互 获取
  2. 日志通过事件来实现
  3. Solidity中,事件是操作触发行为,日志是触发事件后将数据记录在区块链中

事件

事件可以用来做操作记录,存储为日志。主要就是用来记录日志的
关键字:

  • event:创建事件
  • emit:触发事件
pragma solidity ^0.6.0;

contract TestEvent{
    event LogEvent(string _name,uint _age); // 创建一个事件
    
    function emitEvent() public{    // 不能加 pure or view
        emit LogEvent("Muxue",17);  // 触发事件
    }
}

image

事件的主题

  1. 将事件索引化
  2. 一个没主题的事件,无法搜索到
  3. 一个事件,最多有4个主题
    • 事件签名
    • 参数签名
      经过Keccak-256算法加密

简单来说:主题就是为了讲事件索引化,可查询到这个事件

pragma solidity ^0.6.0;

contract TestEvent{
    event LogEvent(string indexed _name,uint indexed _age); // 创建一个事件
    
    function emitEvent() public{    // 不能加 pure or view
        emit LogEvent("Muxue",17);  // 触发事件
    }
}

image

image

异常

  1. 程序编译或运行中发生的错误 即异常
  2. 发生运行时异常,会将之前修改的状态全部还原(0.6.0版本可以选择)
  3. solidity异常
    • 0.4.10之前,throw 条件不满足,中断运行,恢复修改的状态,耗光gas
    • 0.4.10之后,throw废弃,require() ,assert(), revert()代替原来的throw
    • 0.6.0版本,增加了try catch
  4. 功能介绍
    条件检查
    - require():还原状态 返回gas
    - assert():还原状态 耗光gas
    引发异常
    - throw:已经废弃
    - revert():与thorw的区别,允许返回错误原因,可以退回gas
    捕获/处理异常
    - try..catch:只适合于外部调用,
pragma solidity ^0.6.0;

contract TestException{
    uint public data = 100;
    function testThrow(uint _i) public pure{
        //if(_u<10) throw;
    }
    
    function testRequire(uint _i) public{
        data = 200;     // 假如下面引发异常了,会把修改的状态还原回去
        require(_i>10,"_i < 10");
    }
    
    function testAssert(uint _i) public{
        data = 200;     // 假如下面引发异常了,会把修改的状态还原回去
        assert(_i>10);
    }
    
    function testRevert(uint _i) public returns(uint){
        data = 200;     // 假如下面引发异常了,会把修改的状态还原回去
        if(_i<10){
        revert("_i < 10");
        }
        return 12;
    }
    
    event successEvent();
    event failEvent();
    function testTry(uint _i) external returns(uint){
        try this.testRevert( _i ) returns(uint _value){ // 某个函数可能会出现异常, 必须外部调用所以加this. 返回值需要定义一个变量
            // 如果没有异常走这个代码块
            emit successEvent();
            return _value;
        }catch{
             // 如果有异常走这个代码块
             emit failEvent();
        }
    }
}

标签:function,return,Solidity,returns,uint,memory,public
来源: https://www.cnblogs.com/secxue/p/14555704.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有