solidity 语法 - 函数类型

函数类型也是值类型的一种,和C语言中的函数指针类似,用于指向一个函数,可以用于实现回掉等功能。

函数类型分为internalexternal, 标记有internal函数类型只能引用当前contract中的函数,标记有external函数类型可以应用定义在其他contract中的函数。

定义一个函数类型的基本格式如下:

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

有如下几点需要注意:

  • 如果函数类型无返回值,可以将省略returns (<return types>)
  • 函数类型默认为internal类型,internal因此可以省略
  • public函数即可以被作为internal的函数类型使用,也可以作为external类型的函数使用。

两个例子:

pragma solidity ^0.4.23;

contract InternalFuncTest {
     event Error(bytes32 message);
    function caculate(uint p1, uint p2,bool flag) public returns(uint) {
        //The next line will get a compile error since this.add would be consideed as a external function 
        //caculate(p1,p2,flag? this.add : this.sub);
       return caculate(p1,p2,flag? add : sub);
    }
    
    function caculate(uint p1, uint p2, function (uint,uint) internal returns(uint) func ) returns(uint){
        return func(p1,p2);
    }
    
    function add(uint p1, uint p2) public returns(uint) {  
        uint sum = p1 + p2;
        if (sum < p1 || sum < p2){
            emit Error('overflow');
            return 0;
        }
        
        return sum;
    }

    function sub(uint p1, uint p2) public returns(uint) {  
        return p2 < p1 ? p1 -p2 : p2 - p1;
    }
}

上面的例子中,caculate(后一个)的第三个参数是一个internal的函数类型,接受两个uint的参数,并返回一个uint.

pragma solidity ^0.4.23;

contract RequetQueue {
    
    struct Request {
        uint id;
        function (uint,uint) external callback;
    }

    uint constant MAX_LENGTH = 5;
    Request[MAX_LENGTH] queue;
    uint front;
    uint rear;
    bool isEmpty;
    bool isFull;
    
    constructor() public {
          front = 0;
          rear = 0;
          isEmpty = true;
          isFull = false;
    }
    
    function size() public view returns(uint) {
        uint result;
        if (rear > front){
            result = rear - front;
        } else  if(rear > front) {
            result = rear - front + MAX_LENGTH;
        } else {
            result = isEmpty ? 0 : MAX_LENGTH;
        }
        return result;
    }

    function request(uint id, function(uint,uint) external callback) public returns(bool) {
        bool ret = !isFull;
        if (!isFull) {
            queue[rear].id = id;
            queue[rear].callback = callback;
            rear = (rear + 1) % MAX_LENGTH;
            isFull = rear == front;
            isEmpty = false;
        }
        
        return ret;
    }
    
    function process(function(uint) external returns(uint) handler) public returns(bool) {
        bool ret = !isEmpty;
        
        if (!isEmpty) {
            Request storage r = queue[front];
            front = (front + 1) % MAX_LENGTH;
            isFull = false;
            isEmpty = rear == front;
            uint result = handler(r.id);
            r.callback(r.id,result);
        }
        return ret;
    }
    
}

contract Requester {
    
    event PringResult(address msgSender, uint id, uint ret);
    
    RequetQueue queue;
    
    constructor(address externalFunctionTypeTestAddress) public {
        queue = RequetQueue(externalFunctionTypeTestAddress);
    }
    
    function request(uint id) public {
        //Write like this "test.request(id, callback);" will get a compile error cause with out this callback was considered as a internal function
        queue.request(id, this.callback);
    }

    function callback(uint id, uint ret) external {
        emit PringResult(msg.sender,id,ret);
    } 
}

contract Processer {
    
   event Handled(address msgSender, uint val);
    
    RequetQueue queue;
    
    constructor(address externalFunctionTypeTestAddress) public {
        queue = RequetQueue(externalFunctionTypeTestAddress);
    }
    
    function process() public {
        queue.process(this.handler);
    }
    
    function handler(uint val) public returns(uint) {
        emit Handled(msg.sender,val);
        return val + 1;
    }
}

上面的例子RequetQueue定义了一个循环队列,request和process方法分别接受一个external类型,包含一个uint参数,返回值为bool类型的函数。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,490评论 18 139
  • 由于Solidity是一个静态类型的语言,所以编译时需明确指定变量的类型(包括本地变量或状态变量),Solidit...
    yuyangray阅读 1,937评论 2 2
  • 序言本文是 Solidity 文档(以太坊官方 Solidity 开发手册)中文版连载的第五部分。这个连载的前四部...
    风静縠纹平阅读 1,255评论 0 1
  • 有一种目光不远不近, 却一直在守望; 有一种朋友不惊不扰, 却一直在陪同。 你的朋友圈, 她特别关注, 却从未留下...
    MrOrange520阅读 277评论 0 0
  • webpack是什么,提到这个概念,很多人可能立马说出来,模块化加载器兼打包工具,可以把各种资源都作为模块来使用和...
    井皮皮阅读 963评论 0 2