写给开发者Kotlin指引(二)
上一篇说明了Kotlin
的基本语法,本节将深入讲解lambda函数,这是Kotlin
中使用最频繁的进阶技巧。
一、Lambda函数
1.1 基本用法
Lambda函数对于C++
开发者或者Python
不用多解释了,Java
目前也加入了Lambda
的支持。简单来说,Lambda函数就是匿名函数,他可以将函数当成参数传入其他的函数调用中。在C语言中,通过函数指针来实现了这一功能,而在C++中,除了兼容C的函数指针外,还引入了std::function
的标准库支持,另外在Modern C++中还加入了lambda的支持。得益于C++丰富的语意支持,lambda函数的功能异常的丰富,但是也加大了使用的难度。
在Kotlin
中,lambda函数的语法非常简单:
现在通过一个例子说明lambda函数的用法,假设我们需要找到一个字符串数组中长度最大的一个字符串:
这里仔细讲解一下,该函数的返回值是String
,后面的?
表示该函数可能返回一个null
值,listOf
的定义如下:
它是一个泛型函数,我们在调用时需要提供一个类型T
,该类型就是listOf
函数的参数类型,vararg
表示变长参数,我们可以在这里提供多个T
类型的参数。我们在调用时的标准写法应该是listOf<String>("zaabb", "aa", "aaazz")
,但是泛型函数拥有推断能力,由于我们提供的三个参数都是String
类型,所以在调用时可以省略<>
。该函数的函数体很简单,就是将边长参数的所有elements
转化为一个List<T>
。
List<T>
拥有一个maxByOrNull
的方法,来看它的定义:
这是一个内联函数,这个概念在C++中同样存在,就是会将函数在调用处完全展开(C++也不一定会完全展开,编译器会做一些判断,不过用户可以通过一些编译器选项来强制展开)。<T, R : Comparable<R>>
指定了该函数在调用时需要提供哪些类型,而R : Comparable<R>
表示第二个类型R
的类型必须是Comparable<R>
的子类。Iterable<T>.
表示maxByOrNull
函数是Iterable<T>
的一个扩展函数。扩展函数是Kotlin
中的一个新概念,旨在减少Util
类的使用。因为Iterable<T>
本身没有定义maxByOrNull
方法,所以只要在这里补充定义一下,那么就等于Iterable<T>
中定义了一个public
的成员方法。接下来分析该函数的参数,selector
的类型看上去跟lambda
函数的语法非常相似,其实确实是这样,括号中表示该函数接受的参数,为T
,而R
则表示该函数的返回类型,也就是一个Comparable<R>
对象。最后的返回类型是T?
,表示返回的可能是T
类型的变量,也有可能是个null
。
在分析函数体之前,先想一下为什么List<T>
类型的对象能够调用Iterable<T>
的扩展函数maxByOrNull
?根据我们对面向对象的理解,猜测List
应该是Iterable
的子类,通过追踪Kotlin
源代码,发现List
继承于Collection
类,而Collection
类继承于Iterable
类,说明List
是可迭代的。
下面看函数体,第一行调用了iterator()
,它的定义是:public operator fun iterator(): Iterator<T>
,用于返回一个可迭代对象的迭代器,operator
用于标记该函数是一个可重载的运算符函数,这里暂时不细说。iterator
有几个成员函数,用于在可迭代对象中移动迭代器。其中hasNext
用于判断迭代器是否挪到了终点,而next
则指使迭代器挪到可迭代对象中的下一个元素上。这种模式在C++中经常在代码层使用,所以C++开发者应该能够轻易理解这里的意思。不理解的,可以认为就是一个for循环对于List
的遍历。了解了这些细节之后,函数的逻辑就很好理解了,就是通过遍历List
中的所有元素,并通过selector
函数将这些元素都转化为Comparable<R>
对象,然后使用<
来比较他们的大小,并将大的暂时存储到一个临时变量中,整个算法的复杂度是O(N)
。顺便提一下,Comparable<R>
中的<
号也是一个operator
,这就涉及到运算符重载的问题,C++开发者应该能很快领悟其中的奥妙。
1.2 简化调用
其实lambda
函数的调用并不需要先声明出来,所以,上面的代码可以简化为:
Kotlin
还规定,当函数的参数的最后一个参数是函数时,可以将函数参数挪到外面:
当函数只有一个参数,且该参数是函数时,可以省略调函数调用符号,也就是括号:
由于类型推导的存在,我们同样也可以省略s
后面的参数类型:
最后,如果作为参数的函数签名只有一个参数,那么连前面的参数名都可以省略,直接用it
代替即可:
二、总结
lambda
函数大大简化了开发中的冗余代码,而Kotlin
的简洁高效也开始初步展现。(C++:什么叫编程语言的皇冠啊😄)
Last updated
Was this helpful?