lambda表达式杂谈

var personInfo = [ { name: "张三", age: 20, gender: "male" },
        { name: "李四", age: 18, gender: "male" },
        { name: "王五", age: 19, gender: "male" },
        { name: "春香", age: 17, gender: "female" },
        { name: "夏香", age: 21, gender: "female" },
        { name: "秋香", age: 22, gender: "female" },
        { name: "冬香", age: 18, gender: "femalt" }];

 

上面的数据存放着一组人员姓名、年龄、性别相关的信息。 现在有一个需求, 获得年龄20岁以上,性别为女的人的姓名。 看到需求后, 很多人脑袋中产生的解决方案可能是这样的

 

    var result = [];
    for(var i = 0; i < personInfo.length; i++) {
        var item = personInfo[i];
        if( item.age >= 20 && item.gender == "female") {
            result2.push(item.name);
        }
    }
    console.log(result);

 

代码执行的结果是[“夏香”,“秋香”]

 

很好,结果正确,考试的话肯定给满分。

 

但是这种实现方法有点过时,不潇洒,现在流行的做法应该是这样子

 

    let result = personInfo.filter(item=>item.age >= 20 && item.gender == 'female')
                            .map(item=> item.name);
    console.log(result);

 

看, 一样的实现了要求,代码却简洁了许多。如果把代码的实现方式和我们平时的穿着来做对比, 这种实现方式就像是走时尚潮流尖端的穿着打扮,比如说电视里走在t台上的模特的穿着,因为这是es6的语法,由于要兼容老式浏览器的缘故,很多程序员不敢明目张胆的使用。

 

而前一种方法就像是上世纪的中山装,你穿出去没问题,但肯定会被人家说是土鳖。

 

更一般的符合大众审美的写法是这样子的

 

   var result = personInfo.filter(function(item){
        return item.age >= 20 && item.gender == 'female';
    }).map(function(item){
        return item.name;
    });
    console.log(result);

这种写法和第一种写法思路是相同的, 不同点在于,第一种方法使用的是lamda表达式,而这种方法使用的是匿名函数。

 

事实上,匿名函数在功能上和lambda表达式是没有差别的,只是叫法不一样,此外,lambda表达式写法更加简洁一些。

 

在javascript中,lamda表达式可以这样写


()=>{}


而匿名函数要这样写


function(){return;}

 

lambda表达式相对于匿名函数可以省略function和return两个关键字。

 

lambda的原理就是把函数当做另一个函数的参数来使用,以及不用声明这个函数,使用的时候可以直接写。

 

 

这一点我们的老前辈c语言和c++11之前的c++就做不到,在这两位前辈的世界里,要把函数当做参数传递需要使用函数指针, 使用前要先声明函数

 

int callback(int val) {
    return ++val;
}

void test(int (*cb)(int)) {
    int result = cb(100);
    cout << result << endl;
}

int main() {
    test(callback);
    return 0;
}

 

test函数接受一个函数类型参数,callback函数就被作为这个参数传递。 这种写法没什么不好的,就是不够飘逸,就像金庸小说里的武功,这写法如同少林寺的七十二绝技,威力巨大, 却朴实无华,没有如凌波微步、北冥神功、天三六阳掌、天山折梅手这些武功那样吸引观众的眼球。

 

然而, 我们不能怪c和c++不够华丽, 毕竟这两门语言是上古时期的语言,是现在主流计算机语言们的祖宗, 从那个时代的角度去看待这样语言特性,已经是非常先进了。

 

就连之后的后起之秀java也没有做到这样好, java发展出了另一种丧心病狂的模式。 java8之前没有函数指针,没有匿名函数,更加没有lambda表达式。 在java中要实现这种编程模式只能使用类,可以是具名类, 也可以是匿名类, 在java的世界里,函数不能独立存在,它必须依赖于类。

 

于是,要把一个函数当参数传递, 只能传递一个类实例,这个类中再带上这个函数。

 

代码像这个样子

 

abstract class OnClickListener{
public void onClick() {
}
}

protected void onCreate(Bundle savedInstanceState) {  
    btn.setOnClickListener(onclick);  
}  
OnClickListener onclick = new OnClickListener(){  
    @Override  
    public void onClick(View v) { 
//do something
    }  
};  

 

或者这样

 

abstract class OnClickListener{
public void onClick() {
}
}
protected void onCreate(Bundle savedInstanceState) {  
    btn.setOnClickListener(new OnClickListener(){  
        @Override  
        public void onClick(View v) {  
            //do something
        }         
    });  
}  

 

原本几行代码可以搞定的事情却被写成了几十行,而且全是毫无意义的仪式性代码。怪不得人家常说java是用来写大型软件的,尼玛,几行代码硬生生被写成了几十行,这种写法能不大型吗

 

后来的java8支持lambda表达式,改善了这个问题,使java代码简洁了不少,但是那已经是java的第一个版本发布20年以后的事情了, 在这二十年里,不知道让多少java程序员写了多少无用的代码, 做了多少无用功。 但是谁叫它牛逼呢, 常年占据20%的编程语言份额, 死皮赖脸不知上进也没什么,吃老本也饿不死。 看看人家c#, 够上进吧, 还不是连自己的腰都摸不到。

 

说到这里,不得不提一样我们亲爱的世界上最好的语言php,php有匿名函数,但是这个匿名函数算不算lambda表达式呢?从广义的角度去理解,应该算,因为匿名函数和lambda表达式能实现同样的功能。从狭义的角度理解,因该不算,lambda表达式讲究的是飘逸潇洒,匿名函数太臃肿了,如果自认是lambda表达式, 我都替他不好意思。

 

php中的lambda表达式是这样写的

 

function test($callback) {
  $callback();
}

function main() {
   $data = [1,2,3,4,5];
  test(function() use($data){
    //dosomething
  })
}

 

main函数调用test函数传递的就是匿名函数(lambda表达式),这种写法和老式的javascript一样,虽然不优雅,但也挺和谐的。

 

且慢,这个匿名函数为什么带一个use关键字, 这个use关键字是什么鬼?

 

话说php的匿名函数带个use关键字这事吧, 我觉得有好有坏。 php的匿名函数默认是无法访问匿名函数自身作用域除this关键字引用的类实例以外的变量的,从上面的示例来说, 如果不使用use关键字,匿名函数中的代码将无法访问$data变量。 use关键字的作用就是导入这个变量,使匿名函数可以访问它。 所以, 使用不方便,就是use关键字的坏处, 函数用个变量, 还要特定的关键字导入, 坑了个爹。

 

然而,凡事要看两面,使用use关键字也能带来好处。用了use关键字,我们一眼就能看出这个匿名函素用了哪些外部变量,这对代码的可维护性起到一定的正面作用。不过就我个人来讲,还是非常讨厌这个关键字的,我要的是方便,可维护性什么的, 一边玩去,哥揍是这么任性。

 

最后呢,我们聊一聊lambda表达式的集大成者, kotlin。这门语言想必认识的人不多,用的人更少,不过它亲爹做的产品程序员们肯定是家喻户晓的, 如intellij idea、phpstorm、webstorm这些知名IDE都是, 这可都是除visual studio以外最好的集成开发环境了。至于它的干爹,想必知道的人更多,google,成立不到二十年,市值超过微软,智能手机系统安卓就是他家的,可惜他家的拳头产品google搜索引擎,在我们天朝无法使用。

 

kotlin的lambda表达式可以这样写


{}


就一个花括号,连常规的lambda表达式的括号和箭头都省了。 上面那个臃肿的java匿名类,换成kotlin就是这样子

 

protected void onCreate(Bundle savedInstanceState) {  
    btn.setOnClickListener({
    //dosomething
    });  
}  

 

代码量瞬间减少了90%

 

有的同学要问了,这个lambda表达式如何接受参数

 

你可以这样

 

protected void onCreate(Bundle savedInstanceState) {  
    btn.setOnClickListener({ item ->
//dosomething
    });  
}  


这个箭头, 不用的时候可以省略,用的时候可以带上,多么人性化。

 

 

所以,综上所述,论lambda表达式的易用性,kotlin排第二, 就没语言敢排第一。 另外,程序员在编程的时候, 一定要多用lambda,因为这是一种提高生产力的有力工具, 毕竟现在是二十一世纪了,要是再写上世纪80年代的代码,我都替他感到丢人。

 

posted @ 2017-10-09 09:33  陈宏鸿  阅读(1601)  评论(2编辑  收藏  举报