Kotlin 中的函数使用 fun 关键字声明:
fun double(x: Int): Int {
return 2 * x
}
调用函数使用传统的方法:
val result = double(2)
函数参数使用 Pascal
表示法定义,即 name: type
。
参数用逗号隔开。每个参数必须有显式类型:
fun powerOf(number: Int, exponent: Int) { /*……*/ }
函数参数可以有默认值,当省略相应的参数时使用默认值。
与其他语言相比,这可以减少重载方法数量:
// 声明
fun read(b: String, off: Int = 0, len: Int = b.size) { /*……*/ }
// 可通过下面三种方式调用
read("hello")
read("hello", 10)
read("hello", 10, 1024)
默认值通过类型后面的=
及给出的值来定义。
函数的参数(通常是最后一个)可以用 vararg 修饰符标记:
// 声明
fun <T> asList(vararg ts: T): List<T> {
val result = ArrayList<T>()
for (t in ts) // ts is an Array
result.add(t)
return result
}
// 调用
val list = asList(1, 2, 3)
Kotlin
支持局部函数,即一个函数在另一个函数内部:
局部函数可以访问外部函数(即闭包)的局部变量,
所以在上例中,visited
可以是局部变量:
fun dfs(graph: Graph) {
val visited = HashSet<Vertex>()
fun dfs(current: Vertex) {
if (!visited.add(current)) return
for (v in current.neighbors)
dfs(v)
}
dfs(graph.vertices[0])
}
上面提供的 lambda 表达式语法缺少的一个东西是指定函数的返回类型的能力。在大多数情况下,这是不必要的。因为返回类型可以自动推断出来。然而,如果确实需要显式指定,可以使用另一种语法: 匿名函数 。
Lambda 表达式的完整语法形式如下:
val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
高阶函数是将函数用作参数或返回值的函数。
示例来源:
https://juejin.im/post/5b198c675188257d7a49b3ec
// 源代码
fun test(a : Int , b : Int) : Int{
return a + b
}
fun sum(num1 : Int , num2 : Int) : Int{
return num1 + num2
}
// 调用
test(10,sum(3,5)) // 结果为:18
在函数块内可以通过
it
指代该对象。
常见写法let
函数处理需要针对一个可null
的对象统一做判空处理
mVideoPlayer?.setVideoView(activity.course_video_view)
mVideoPlayer?.setControllerView(activity.course_video_controller_view)
mVideoPlayer?.setCurtainView(activity.course_video_curtain_view)
// 上面的写法可以使用 it 指代该对象改为下面的写法
mVideoPlayer?.let {
it.setVideoView(activity.course_video_view)
it.setControllerView(activity.course_video_controller_view)
it.setCurtainView(activity.course_video_curtain_view)
}
它是将某对象作为函数的参数,在函数块内可以通过
this
指代该对象。返回值为函数块的最后一行或指定return
表达式
适用于调用同一个类的多个方法时,可以省去类名重复,直接调用类的方法即可
经常用于Android RecyclerView onBinderViewHolder
中,数据model
的属性映射到UI
上
override fun onBindViewHolder(holder: ViewHolder, position: Int){
val item = getItem(position)?: return
with(item){
holder.nameView.text = "姓名:$name"
holder.ageView.text = "年龄:$age"
}
}
实际上可以说是
let和with
两个函数的结合体,run
函数只接收一个lambda
函数为参数,以闭包形式返回,返回值为最后一行的值或者指定的return
的表达式 ,适用于let, with
函数任何场景。
run
函数弥补了let
函数在函数体内必须使用it
参数替代对象,也可以像with
函数一样可以省略,直接访问实例的公有属性和方法,另一方面它弥补了with
函数传入对象判空问题,在run
函数中也可以像let
函数一样做判空处理
override fun onBindViewHolder(holder: ViewHolder, position: Int){
val item = getItem(position)?: return
item?.run {
holder.nameView.text = "姓名:$name"
holder.ageView.text = "年龄:$age"
}
}
从结构上来看
apply
函数和run
函数很像,唯一不同点就是它们各自返回的值不一样,run
函数是以闭包形式返回最后一行代码的值,而apply
函数返回的是传入对象的本身
apply
一般用于一个对象实例初始化的时候,需要对对象中的属性进行赋值。或者动态inflate
出一个XML
的View
的时候需要给View
绑定数据也会用到,这种情景非常常见
// 返回对象本身
val person = Person("Tom", 100).apply {
name = "Aller"
age = 50
}
// view 初始化
mRootView = View.inflate(activity, R.layout.example_view, null).apply {
tv_cancel.paint.isFakeBoldText = true
tv_confirm.paint.isFakeBoldText = true
seek_bar.max = 10
seek_bar.progress = 0
}
also
函数的结构实际上和let
很像,唯一的区别就是返回值的不一样。let
是以闭包的形式返回,返回函数体内最后一行的值,如果最后一行为空就返回一个Unit
类型的默认值。
而also
函数返回的则是传入对象的本身。适用于let
函数的任何场景,also
函数和let
很像,只是唯一的不同点就是let
函数最后的返回值是最后一行的返回值而also
函数的返回值是返回当前的这个对象。一般可用于多个扩展函数链式调用
fun main() {
val result = "Tom".also {
println(it.length)
}
println(result) // 打印:Tom
}
Kotlin 编译器会将内联函数中的代码在编译时自动替换到调用它的地方,这样就不存在运行时的开销了。
**一般会把高阶函数声明为内联函数,**即在定义高阶函数时加上inline
关键字声明,这是一种良好的编程习惯,绝大多数高阶函数是可以直接声明成内联函数的。
参考:
https://blog.csdn.net/LucasXu01/article/details/106163092
inline fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
val result = operation(num1, num2)
return result
}
Kotlin 有个特别好用的功能叫扩展,你可以给已有的类去额外添加函数和属性,而且既不需要改源码也不需要写子类。
声明一个扩展函数,我们需要用一个 接收者类型 也就是被扩展的类型来作为他的前缀。
参考:https://www.kotlincn.net/docs/reference/extensions.html
下面代码为MutableList
添加一个swap
函数:
// 声明
fun MutableList<Int>.swap(index1: Int, index2: Int) {
val tmp = this[index1] // “this”对应该列表
this[index1] = this[index2]
this[index2] = tmp
}
// 使用
val list = mutableListOf(1, 2, 3)
list.swap(0, 2) // “swap()”内部的“this”会保存“list”的值
如果一个类定义有一个成员函数与一个扩展函数,而这两个函数又有相同的接收者类型、 相同的名字,并且都适用给定的参数,这种情况总是取成员函数。 例如:
class Example {
fun printFunctionType() { println("Class method") }
}
fun Example.printFunctionType() { println("Extension function") }
Example().printFunctionType()
输出:
“Class method”。
fun
开头声明,有可选参数、命名参数、可变长参数inline
内联函数来规避。