Soildity之函数(4)

Soildity中,一个函数可以支持多个参数,同时也支持用于多个返回值,如果没有对返回值进行赋值默认为0。函数定义的模型如下:
function () {internal|external} [pure|constant|view|payable] [returns ()]
下面给出简单的示例:

contract SimpleContract{
	function cal(uint a,uint b) returns(uint sum,uint product){
		sum = a+b;
		product = a*b;
		//或者使用 return (a+b,a*b)
	}
}
对于普通的函数调用,其传入的参数顺序必须与声明时一致。在Soildity语言中,对函数的调用提供一种特殊的调用方式,命名调用,示例如下:
contract SimpleContract{
	function foo(uint a,uint b) {
	      ...
	}
   
   function g(){
   		foo({b:3,a:2});
   }
}

Soildity针对函数和变量提供几种修饰词,如下:
external:用于修饰函数,表示函数为一个外部函数,外部函数是合约接口的一部分,这以为着只能通过其他合约发送交易的方 式调用外部函数。
public:用于修饰公开的函数和变量,表示该函数和变量既可以在合约外部访问,也可以在合约内部访问。
internal:内部函数和变量,表示只能在当前的合约或者继承当前合约的其他合约中访问。
private:私有函数和变量,只有当前的合约内部才可以访问。

注:在Soildity中函数依据调用方式的不同可分为内部调用和外部调用:
内部调用:调用同一合约中的函数,对应的EVM指令集中的JUMP指令,所有效率非常高,在此期间内存不会被回收。
外部调用:创建一个消息发送给被调用的合约。

1. pure
函数可以声明为 pure ,在这种情况下,承诺不读取或修改状态。
在以太坊中,以下被认为是从状态中读取:
a.读取状态变量
b.访问 this.balance 或者

.balance
c.访问 block,tx, msg 中任意成员 (除 msg.sig 和 msg.data 之外)
d.调用任何未标记为 pure 的函数
e.使用包含某些操作码的内联汇编
其示例代码如下:

pragma solidity ^0.4.16;

contract C {
    function f(uint a, uint b) public pure returns (uint) {
        return a * (b + 42);
    }
}

2. constant函数
在Soildity语言中,声明函数携带constant或者view关键字说明这个函数进行的是只读操作,不会造成其他的状态变化。即不会修改变量值、触发相关事件、创建其他合约、调用任何非constant函数。示例函数如下:

```
contract SimpleContract{
	function f(uint a,uint b) view returns(uint){
		return (a+b);
	}
}
```

3. payable函数
在以太坊合约中,只有带有payable的函数才能进行以太币的转账,其示例代码如下:

	contract SimpleContract{
		function SimpleContract() payable{
			...
		}
	}

4. fallback函数
fallback也成为回退函数,是合约里的特殊函数,没有名字,不能有参数,没有返回值。当一个合约收到无法匹配的任何函数名时,fallback会被自动执行。在每个合约中,都有一个默认隐式的fallback函数,其定义如下:

	function (){
				...   //可自己编写代码用于相关功能的实现
			}

在Soildity0.4.0版本后,合约可以结合fallback函数加上payable修饰词进行以太币转账,源码实现如下:

	```
			//要接收以太币,合约里面必须要有payable关键字
			//当我们使用address.send(ether to send)向某个合约直接转帐时,由于这个行为没有发送任何数据
		    //所以接收合约总是会调用fallback函数
			 function () external payable {
			    require(msg.sender != address(0));
			    require(msg.value != 0);
			    ...  //代码实现
			  }
	
	```
fallback()函数为了防止外部攻击和合约漏洞,规定了此函数通过send()方式调用只能消耗2300gas。超过2300gas函数就会执			行失败。对使用call()方式或者其他的操作没有这样的限制。

5. 函数修改器modifier
函数修改器可以一定程度上改变函数的行为。可以作为函数执行的先行条件,如果符合函数修改器定义的条件,才可以执行函数体内容。关于函数修改器,可以把理解成if的变相。其定义语法如下:

```
modifier 修改器名 {
        条件体..
        _;  //待执行的代码函数体
    }

    function a() 修改器名 {
        函数体..
    }
    
	示例如下:
	
	pragma solidity ^0.4.0;
	//权限控制
    contract Ownable {
		 address public owner = msg.sender;
		 // @notice 检查必须是合约的所有者
		 modifier onlyOwner {
		 if (msg.sender != owner) throw;
		 _;
	  }
	 
	 // @notice 改变合约的拥有者身份
     // @param _newOwner 新所有者的地址
     function changeOwner(address _newOwner) onlyOwner {
    	 if(_newOwner == 0x0) throw;
    	 owner = _newOwner;
	 	}
	}
```
当要执行a()时,会先去执行修改器,判断条件体,如果符合条件,才会继续执行a();如果不符合条件,a()将不执行。”_;”在这里表示的是a(). 
	函数修改器可以接收上下文中存在的任意变量组成的表达式,直接在函数修改器中传入参数。示例如下:
```
modifier 修改器名(uint 参数1, string 参数2) {
        if(参数1>10 && 参数2 != "男")
        //条件体..
        _;
    }
```
当函数的修改器条件判断不成功,如果函数没有返回值,对应的函数将不执行;如果函数有返回值,那将返回对应类型的默认值。而函数修改器中的条件体,不论函数是否符合条件,都会继续执行完毕修改器中的后续逻辑。 
当一个函数拥有多个函数修改器时,执行顺序是按照先后顺序依次执行。如果有一个不满足,函数即不能执行。如下:
```
pragma solidity ^0.4.0;

contract Test{
  modifier A(uint a) {
    if(a<10) throw;
    _;
  }

  modifier B(uint b) {
    if(b<10) throw;
    _;
  }

  //必须同时满足A、B,才能执行f()
  function f(uint a, uint b) A(a) B(b) returns(uint) {
      return 777;
  }
}
```

6. 事件
事件是能方便地调用以太坊虚拟机日志功能的接口,其函数定义如下:

pragma solidity ^0.4.21;
contract SimpleAuction {
    event HighestBidIncreased(address bidder, uint amount); // 事件

    function bid() public payable {
        // ...
        emit HighestBidIncreased(msg.sender, msg.value); // 触发事件
    }
}

其中 event 是定义事件的关键词,emit 是触发事件的关键词。关于以太坊事件与合约的定义,请参照:
https://blog.csdn.net/u010304442/article/details/88975894

7. 异常处理
以太坊使用状态回退机制来处理异常,即当前发送错误,当前消息调用和子消息调用产生的所有变化都将被撤回并且返回调用者一个报错的信号。
Soildity语言提供assert函数通常用于检查变量和内部错误;require函数用于确保程序执行的必要条件是成立的。
对于assert类型的异常场景:(异常发生执行回退操作的指令号:0xfe)
a.访问数组越界,下标为负数或者超出长度
b.对0做除法或者对0取模
c.进行移位操作时给出一个负数
d.将一个过大的数或者负数转换到枚举类型
e.调用assert函数并且参数值为false

 对于require类型的异常场景:(异常发生执行回退操作的指令号:0xfd)
 	a.调用throw
 	b.调用require并且参数值为false
 	c.发起一个消息,但这个调用执行失败,如Gas耗尽、被调用函数不存在
 	d.调用外部函数时指向一个不包含合约的地址

revert函数和throw关键字会标识发生了错误,并且回退当前的消息调用产生的状态改变!

你可能感兴趣的:(solidity)