一起学智能合约之五函数和修改器

一起学智能合约之五函数和修改器

 

函数是所有的语言都离不开的。其实在上面的表达式里就简单的说明了函数的一些形式和用法,这里再整体说明一下。

Solidity的函数形式如下:

function (<parameter types>) {internal|external} [pure|constant|view|payable] [returns (<return types>)]

function 函数名(参数列表){调用修饰符}[函数属性][返回值列表]

看一个实例:

pragma solidity ^0.4.16;

 

contract C {

    function g(uint a) public pure returns (uint ret) { return f(); }

    function f() internal pure returns (uint ret) { return g(7) + f(); }

}

和上面的一对应就明白怎么回事了。现在主要介绍一下函数的高级用法:

  1. Solidity封装了两种函数的调用方式internal和external。

1)内部函数调用

当前合约中的函数可以直接(“从内部”)调用,也可以递归调用,就像下边这个荒谬的例子一样

pragma solidity ^0.4.16;

 

contract C {

    function g(uint a) public pure returns (uint ret) { return f(); }

    function f() internal pure returns (uint ret) { return g(7) + f(); }

}

 

这些函数调用在 EVM 中被解释为简单的跳转。这样做的效果就是当前内存不会被清除,也就是说,通过内部调用在函数之间传递内存引用是非常有效的。

2)外部函数调用

如果想要调用其他合约的函数,需要外部调用。对于一个外部调用,所有的函数参数都需要被复制到内存。虽然下面两个合约写到了一起,但和不写在一些,部署到链上的结果是一致的。

pragma solidity ^0.4.0;

 

contract InfoFeed {

    function info() public payable returns (uint ret) { return 42; }

}

 

contract Consumer {

    InfoFeed feed;

    function setFeed(address addr) public { feed = InfoFeed(addr); }

    function callFeed() public { feed.info.value(10).gas(800)(); }

}

 

说明:payable 修饰符要用于修饰 info,否则,.value() 选项将不可用。

external调用时,实际是向目标合约发送一个消息调用。消息中的函数定义部分是一个24字节大小的消息体,20字节为地址,4字节为函数签名2。如果被调函数所在合约不存在(也就是账户中不包含代码)或者被调用合约本身抛出异常或者 gas 用完等,函数调用会抛出异常。

3)this关键字

可以使用this关键字来强制以external方式的调用。注意,不可以在构造函数中通过 this 来调用函数,因为此时真实的合约实例还没有被创建。

4)具名调用和匿名函数参数

函数调用参数也可以按照任意顺序由名称给出,如果它们被包含在 {} 中, 如以下示例中所示。参数列表必须按名称与函数声明中的参数列表相符,但可以按任意顺序排列。

pragma solidity ^0.4.0;

 

contract C {

    function f(uint key, uint value) public {

        // ...

    }

 

    function g() public {

        // 具名参数

        f({value: 2, key: 3});

    }

}

5)函数重载

类似于大多数面向对象编程的语言,Solidity也是支持函数的重载的。

contract Simple {

    function func(uint num) public pure returns (uint count) {

        return  1;

    }

 

    function func(uint num, int id) public pure returns (uint count) {

        return 2;

    }

}

  1. Solidity为函数提供了四种可见性,external,public,internal,private。

1)external

external关键字表示合约函数调用的其它合约或者在交易中调用。在接收比较大的数组时性能可能会好一些。

2)public

函数默认声明为public。

这个没啥限制,想怎么访问就怎么访问,这其实相当于API。

3)internal

类似于protected,在本合约和继承合约中,只允许以internal的方式调用。

4)private

类似其它语言,只能在本合约中被访问(继承合约不可访问)。但是按照区块链的特性,其仍然可以被查看,只是不能被访问。

pragma solidity ^0.4.5;

 

contract Base{

    //指定私有

    function privateFun() private{}

 

    function callFun(){

        //内部调用

        privateFun();

    }

}

contract Simple is Base{

    //错误

    function callFun(){

        //privateFun();

    }

}

 

3、回退函数fallback

每个合约有且仅有一个没有名字的函数。函数没有参数和返回值。如果调用合约时,没有找到其它函数,即调用fallback函数。

另外,如果想对合约直接转帐(send()函数发送ether),那么这个回退函数也会执行。可以认为它是一个默认的接收函数。但为了安全起见,应该让此函数执行较少的动作。同时,限制此函数对gas的使用。(理论是2300gas)

所以在下列的操作中,都无法在fallback函数中执行,因为耗费的gas超过了2300。

1. 写入到存储(storage);

2. 创建一个合约;

3. 执行一个外部(external)函数调用,会花费非常多的gas;

4. 发送ether。

所以在部署合约前一定要进行安全测试,防止Gas超标,如果没有定义回退函数,那么向其发送以太坊,会引起异常并退回相应的以太坊(V0.4.0开始)。

pragma solidity ^0.4.0;

 

contract Simple{

  function(){

    //fallback function

  }

}

 

4、修改器modifier

函数修改器类似于SpringMVC的增强(前置增强,后置增强,环绕增强),其实说白了就是简单的代码重用技术,没有任何高深的知识。

修改器(Modifiers)可以用来改变一个函数的行为。比如用于在函数执行前检查某种前置条件。修改器是一种合约属性,可被继承,同时还可被派生的合约重写(override)。

下面是一个官网的防止重入的例子:

pragma solidity ^0.4.0;

contract Mutex {

    bool locked;

    modifier noReentrancy() {

        if (locked) throw;

        locked = true;

        _;

        locked = false;

    }

 

    /// This function is protected by a mutex, which means that

    /// reentrant calls from within msg.sender.call cannot call f again.

    /// The `return 7` statement assigns 7 to the return value but still

    /// executes the statement `locked = false` in the modifier.

    function f() noReentrancy returns (uint) {

        if (!msg.sender.call()) throw;

        return 7;

    }

}

5、总结

从上面的分析来看,Solidity的函数并没有什么高深的知识,只要是掌握其它语言,学习这个应该是很简单的,不过需要注意的是,要把一些细节吃透,防止出现异常。现在黑客越来越生猛,一不小心,就被割韭菜了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值