当前位置: 首页 > 科技观察

Kotlin函数与函数式编程浅析

时间:2023-03-16 02:11:58 科技观察

如果你对Kotlin语法一窍不通,建议先阅读官方文档或中文网(https://www.kotlincn.net/docs/reference/)阅读这篇文章会有更深刻的理解。本文主要介绍Kotlin函数的使用和函数式编程的一些理解。并且会与Python和C++做一些比较。以下是维基百科上对函数式编程的定义:函数式编程(英文:functionalprogramming),即函数式编程,又称函数式编程,是一种将计算机操作当作数学函数计算的编程范式,并避免程序状态和可变对象.函数式编程语言最重要的基础是lambda演算。并且lambda演算的函数可以接受函数作为输入(参数)和输出(传出值)。下面是高阶函数的定义:在数学和计算机科学中,高阶函数是至少满足以下条件之一的函数:接受一个或多个函数作为输入,并输出一个函数。不难推断,函数式编程最重要的基础是高阶函数。也就是说,支持函数可以接受函数作为输入(参数)和输出(传出值)。作为Kotlin中的一等公民,函数可以像其他对象一样作为函数的输入和输出。这是Java程序员转Kotlin最难的一点。如果你之前学过Python或者C++11,可能会更容易接受这一点。这也是为什么本文着重介绍Kotlin的函数和函数式编程的原因。Kotlin函数以下是Kotlin中的通用函数定义。和Java不同的是函数参数和返回值类型放在后面。函数体可以用等号赋值给函数定义,这里也可以看出函数和变量的相等性。funmain(args:Array){vars=sum(1,2)varm=multi(2,3)varx=maxOf(3,4)}funsum(a:Int,b:Int):Int{returna+b}funmulti(a:Int,b:Int):Int=a*bfunmaxOf(a:Int,b:Int):Int=if(a>b)aelseb此外,Kotlin还支持函数默认参数、扩展函数、中缀表达式、这是一个简单的例子:funmain(args:Array){isBiggerThan(2)isBiggerThan(2,5)vars="a".isLetter()vara=1add2}funisBiggerThan(a:Int,b:Int=0){returna>b}//扩展函数funString.isLetter():Boolean{returnmatches(Regex("^[a-z|A-Z]$"))}//扩展函数,中缀表达式infixfunInt.add(x:Int):Int{returnthis+x}支持默认参数的函数可以减少函数重载。String对象中没有判断是否为字母的方法。在Java中,我们一般会定义一些Utils方法,但是在Kotlin中,我们可以定义类扩展函数。第二个例子是为Int类定义一个扩展函数,扩展函数用中缀表达式表示,赋予开发者定义类似关键字的权利。例如,我们可以这样创建一个地图对象:valkv=mapOf("a"to1,"b"to2)其中to是一个中缀表达式,定义如下:publicinfixfunA.to(that:B):Pair=Pair(this,that)Pair是Map中存储的对象,所以也可以创建valkv=mapOf(Pair("a",1),Pair("b",2))在Python中,如果我们希望函数返回多个值,我们可以返回一个元组。Kotlin也可以根据解构原理实现类似的功能:funmain(args:Array){val(index,count)=findWhere("abcabcabcabc",'c')}funfindWhere(str:String,findChar:Char):Pair{varindex=-1varcount=0for((i,v)instr.withIndex()){if(v==findChar){if(index==-1){index=i}++count}}returnPair(index,count)}如何支持自定义对象的解构,请参考官方文档,map支持解构,所以可以这样遍历:for((k,v)inmap){print("$k->$v,")}高阶函数和Lambda表达式“Lambda表达式”(lambda表达式)是匿名函数,Lambda表达式是基于数学中的lambda演算名称直接对应lambda抽象(lambdaabstraction),这是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意与传统数学意义上的区别)。Python中的Lambda表达式:C++中的add=lambdax,y:x+ylambda:[](intx,inty)->int{returnx+y;}Kotlin中的lambda:varadd={x:Int,y:Int->x+y}作为强类型语言,Kotlin相对简洁。我们可以像这样使用lambda表达式:funmain(args:Array){valsumLambda={a:Int,b:Int->a+b}sumLambda(1,2)}它可以像使用()中的函数一样调用kotlin中的运算符是可以重载的,()运算符对应类的重载函数invoke()。也可以这样定义一个变量:valnumFun:(a:Int,b:Int)->Int不是普通变量,它必须指向一个函数,并且函数签名必须一致:funmain(args:Array){valsumLambda={a:Int,b:Int->a+b}varnumFun:(a:Int,b:Int)->IntnumFun={a:Int,b:Int->a+b}numFun=sumLambdanumFun=::sumnumFun(1,2)}funsum(a:Int,b:Int):Int{returna+b}可以看到这个变量可以等于一个lambda表达式,或者另一个lambda表达式变量,或者等于一个普通的函数,但是需要在函数名前加(::)来获取函数引用。这类似于C++中的函数指针,但是在Python中,函数名可以直接作为函数引用。以下是C++函数指针的示例:#includeusingnamespacestd;voidswap(int&x,int&y);intmain(intarg,char*args[]){intx=10;inty=20;void(*methodPtr)(int&x,int&y);//声明一个函数指针methodPtr=&swap;//函数指针赋值methodPtr=swap;//取地址符可以省略,效果和上面一致methodPtr(x,y);//像给别名一样对于函数,可以直接用()调用cout<<"x:"<Any){for(iteminlist){function(item)}}***第一个参数是一个List,第二个参数是一个函数,目的是将List中的每一项元素转换为执行一次第二个函数。使用方法如下:valstrList=listOf("h","e","1","a","b","2","","","c","5","7","F")doMap(strList,{item->print("item:${upperLetter(item)},")})funupperLetter(item:String):String{if(item.isLetter()){returnitem.toUpperCase()}returnitem}第二个参数直接传入lambda表达式,当然也可以传入函数引用:valstrList=listOf("h","e","1","a","b","2","","","c","5","7","F")doMap(strList,::printUpperLetter)funprintUpperLetter(item:String){print("item:${upperLetter(item)},")}funupperLetter(item:String):String{if(item.isLetter()){returnitem.toUpperCase()}returnitem}与上述代码效果相同。在C++中使用函数指针可以实现类似的效果:usingnamespacestd;voidmMap(vectorlist,void(*fun)(intitem));intmain(intarg,char*args[]){vectorlist={2,3,4,3,2,1,2};mMap(list,[](intitem)->void{cout<T){valresult=function()println("result->$result")}有点像gradle的配置文件,所以Kotlin可以很方便编写领域特定语言(DSL)。此外,Kotlin还支持本地函数和函数作为返回值。见如下代码:funmain(args:Array){valaddResult=lateAdd(2,4)addResult()}//局部函数,函数引用funlateAdd(a:Int,b:Int):Function0{funadd():Int{returna+b}return::add}在lateAdd内部定义了一个局部函数,***返回局部函数的引用,对结果使用()运算符得到最终结果,达到延迟计算的目的。作为一等公民,函数当然可以像普通对象一样放入map中,比如:valfuns=mapOf("sum"to::sum)valmapFun=funs["sum"]if(mapFun!=null){valresult=mapFun(1,2)println("sumresult->$result")}funsum(a:Int,b:Int):Int{returna+b}将函数引用作为值放入映射中,并且取出后使用()运算符调用可以简化一些if和else场景。基于以上函数式编程的特点,Kotlin可以像RxJava一样方便的进行相应的编程,例如:item->item.isNotBlank()}.filter{item->if(item.isNullOrEmpty()){return@filterfalse}return@filteritem.matches(Regex("^[a-z|A-Z]$"))}。filter{it.isLetter()}.map(String::toUpperCase).sortedBy{it}.forEach{print("$it,")}println()}以上代码只是为了演示,没有实际意义。具体语法请查看官方文档。相信Kotlin作为一门强类型的现代语言,在保证稳定性的同时,能够极大的提升开发者的开发效率。

最新推荐
猜你喜欢