大家好,我是up通,通学技术,学通技术,欢迎大家继续跟我一起学习智能合约系列。
在实战篇当中,我们将重点介绍solidiy
函数的特性。solidity
学了这么久,我们会发现其实和java
这种面向对象的语言还是很类似的,java
类对应solidity
合约。而合约的属性及函数正对应了我们java
的成员变量及成员方法。编程玩的是逻辑,而逻辑的体现则是行为,行为的数字描述则是函数。
我们将花费巨量的篇幅来说明solidty
的函数,一起加油吧。
solidity
函数的标准形式我们可以概括如下:
function functionName() {private|internal|external|public} [pure|constant|view|payable] [returns()]
在学习java
的时候,也有重载的概念。正所谓当我们的一些行为模式一致时,但是当这个行为所输入的参数不一样时,便构成了重载
。具体表现如下:
具体我们来看一下代码:
pragma solidity ^0.4.16;
contract overLoadTest{
// 不带参数
function test(){
}
// 带一个参数
function test(address account){
}
// 参数类型不同--uint160可以和address直接转化 但仍然满足重载的条件
function test(uint160 account){
}
// 参数个数不同
function test(uint160 account,address otherAccount){
}
// 此方法放开注释会编译报错,因为重载并不关心返回结果(不考虑函数的返回值是否相同)
// function test(address account) returns(address sender){
// return msg.sender;
// }
}
重载虽然优雅,但是以下这种情况要注意呐!!!
uint public result = 0;
function negativeExample1(uint id){
result = 100;
}
function negativeExample1(uint8 id){
result = 200;
}
function test1(){
negativeExample1(1);
}
编译上述代码后,编译器会提示我们如下错误:
browser/Math.sol:40:9: TypeError: No unique declaration found after argument-dependent lookup.
negativeExample1(1);
^--------------^
意思就是说,在调用test1
函数的时候,编译器检查了函数入参发现声明不唯一。因为我们的1
既可以用uint
接收,也可以用uint8
来接收。
但是当我们调用negativeExample(256)
的时候编译过程就不会报错了,这个时候只能接收最大值为255的uint8
就无能为力了。
那么针对我们的address
和uint160
,是不是也是如此呢?
在前面的以太坊地址的本质内容中,我们介绍过,address
本质上就是一个uint160
的一串数字。所以显然也会发生上述同样的问题。
function negativeExample2(address account){
result = 100;
}
function negativeExample2(uint160 account){
result = 200;
}
// 此处放开注释 自动编译报错
//function test2(){
// negativeExample2(256);
//}
所以在我们写合约的过程中,要注意这种情况,杜绝此类写法。
pragma solidity ^0.4.16;
contract functionParamTest{
uint public id;
string public name;
function setParam(uint _id,string _name){
id = _id;
name = _name;
}
function test(){
setParam(18,"xiaofang");
}
function test2(){
setParam({
_id:18,_name:"xiaofang"});
}
function test3(){
setParam({
_name:"xiaofang",_id:18});
}
// 编译报错
// function test4(){
// setParam(18);
// }
}
在solidity
中,为我们提供了一种命名参数
给函数赋值的方式,相对来说,更加灵活,当参数多的时候,优势就体现出来了。
另外在我们写合约的时候,调用函数时参数个数必须是相同的,但是在外部调用的时候,我们可以少传参数(很不建议)
,如下图:
命名参数还是比较简单的,我们就介绍到这里。
哦,对了。差点忘了,这里讲一个开发小规范哈:
solidity 内部函数参数通常会加_
solidity
, sao还是你sao。
至于怎么sao,来看下面这段代码。
pragma solidity ^0.4.16;
contract functionReturnTest{
// 最常规的返回值写法
function test() view returns(uint){
return 10;
}
// 返回值也可以进行一个命名
function test1() view returns(uint result){
return result;
}
// 可以返回任意匹配类型的值
function test2() view returns(uint result){
uint a = 10;
result = 100;
return a;
}
// 可以返回任意匹配类型的值2
function test3() view returns(uint result){
uint a = 10;
result = 100;
return 1;
}
// 可以返回多个参数 不用加return 必须要给返回值赋值
function test4(uint a,uint b) view returns(uint add,uint multiply){
add = a+b;
multiply = a*b;
}
// 可以返回多个参数的简写
function test5(uint a,uint b) view returns(uint add,uint multiply){
return (a+b,a*b);
}
// 可以直接进行一个交换操作
function test6(uint a,uint b) view returns(uint _b, uint _a){
return (b,a);
}
// 可以直接返回任意匹配多个参数的值
function test7() view returns(uint a,uint b){
return (10,6);
}
}
此处,关于返回值的灵活写法,让我觉得又有点像python
。但相对来说,还是挺工整的。下面我们看看这个执行结果。
好了 ,关于返回值的特性,也就介绍到这里,相对来说,也是比较简单的。
针对于有编程经验的人呢,这个内容就不用过多解释了。
针对没有编程经验的人呢,只要记住作用范围是通过{}
来划分的即可。
下面的代码大家可以直接执行理解即可。
pragma solidity ^0.4.16;
contract scopeTest{
uint public a = 100;
uint b = 200;
//uint a = 100;
function test() view returns(uint){
uint a = 300;
a = 700;
return a;
}
function test2(uint a) view returns(uint){
//uint a;
// for(uint a = 0; a<5;a++){
// }
{
// uint a;
a = 700;
return a;
}
}
}
作用域头生、作用域尾死。