这篇主要讲讲kotlin里面的各种函数
- 简化函数
所谓的简化函数是假如执行代码提就只是一行代码或者是单行表达式,一行就可以搞得的,就可以进行简化
fun myMethod()= print("jack")
就这样,一句代码的时候就直接用=就可以实现,或者在单行表达式时:
fun myMethod2(count:Int)=if(count>2) {
var data=myMethod()
"jack1$data"
} else {
"jack2"
}
- 匿名函数
定义时不取名字的函数,我们称之为匿名函数
- 定义时不取名字的函数,我们称之为匿名函数,匿名函数通常整体传递给其他函数或者从其他函数返回
- 和函数不一样,匿名函数通常不需要return关键字返回数据。匿名函数会隐式的或自动返回最后一行代码的执行结果。
val myMethod:()->String={
"jack"
}
fun main(){
myMethod
}
这样就可以直接调,当又参数时:
//单个参数
val myMethod:(name:String)->String={
it+"jack"
}
//多个参数
val myMethod:(name:String,age:Int)->String={n:String,a:Int->
n+"jack"+a
}
当我们把匿名函数赋值给变量时,也可以不用指定函数的返回值类型,有编译器进行类型推断。
//没有参数
val myMethod={
"jack"
}
//一个参数时:
val myMethod={name:String->
name+"jack"
}
//多个参数时:
val myMethod={name:String,age:Int->
name+"jack"+age
}
- 高阶函数
将函数用作参数或返回值的函数
fun test(name:String,age:Int,getAge:(age:Int)->String){
var data=name+getAge(age)
Log.e("test",data)
}
fun main(){
test("Jack",12){
it.toString()+"你好"
}
}
输出的结果为 E/test: Jack12你好
, 也可以独立出一个匿名函数:
val getAgeFun:(age:Int)->String={
it.toString()+"你好"
}
- 闭包
一段程序代码通常由变量,常量,表达式组成,然后使用一堆"{}"来闭合,并包裹这些代码,由这对花括号包裹着的代码就是闭包。函数,Lambda,if语句,when语句都可以称之为闭包,但通常情况下我们所说的闭包就是Lambda
fun test():(age:Int)->Int{
var a = 1//状态
return {
var data=a+it
Log.e("test",data.toString())
data
}
}
fun main(){
val funTest=test()
funTest(1)
funTest(2)
funTest(3)
funTest(4)
}
函数内部的局部变量的状态保存了,变量的值就是状态,而返回值可以闭包捕获的变量可以脱离原始作用域而存在:
fun test5():()->Int{
var a = 1//状态
return {
a++
Log.e("test",a.toString())
a
}
}
- 局部函数
即在函数里嵌套函数,函数里面有函数。
fun test1(name:String,age:Int){
fun test2(ageTest:Int):String{
return ageTest.toString()
}
var data=test2(age)
println(name+data)
}
fun main(){
test1("jack",12)
}
运行结果System.out: jack12
- 顶层函数
Kotlin 允许在文件内直接定义函数,这个方法可以被称为顶层函数。
// Test.kt
fun test(string: String) {
println("this is top function for $string")
}
这种函数可以在 Kotlin 中被直接调用,无需指定其实例或类名.
- 运算符重载函数
就是对已有的运算符赋予他们新的含义
data class Person(var name: String, var age: Int)
operator fun Int.minus(p: Person) = this - p.age
可以被重载运算符
表示 | 重载 |
---|---|
a = a + b | a = a.plus(b) |
a = a - b | a = a.minus(b) |
a = a * b | a = a.tiems(b) |
a = a / b | a = a.div(b) |
a = a % b | a = a.rem(b) |
a … b | a.rangTo(b) |
a % b | a.rem(b) 或 a.mod(b) |
++a, a++ | inc |
!a | not |
a > b | a.compareTo(b) > 0 |
a < b | a.compareTo(b) < 0 |
a >= b | a.compareTo(b) >= 0 |
a in b | b.contains(a) |
a !in b | !b.contains(a) |
Kotlin中的 && 、 || 、 ?: 、 === 、 !== 是不能被重载的
- 内联函数
inline
用inline 修饰的方法,当又地方调用它时,把这个函数方法体中的所以代码移动到调用的地方,而不是通过方法间压栈进栈的方式,可以提高代码效率,当时也会照常编译的时候代码臃肿。
inline fun test(){
println("inline fun")
}
fun main(){
test()
}
在实际的编译后,其实代码变成如下这样:
fun main(){
println("inline fun")
}
这样看还不知道内联函数有啥优势,毕竟这么做虽然会提高点运行效率,但是也会造成编译代码变多,那为啥要有内联函数呢?,先看如下代码:
inline fun test(printAction:()->Unit){
println("inline fun")
printAction()
}
fun main(){
test{
println("hello")
}
}
我们用高阶函数定义了一个printAction()函数,但是printAction()是一个对象,假如我们一个for循环不断调用test(printAction:()->Unit)
方法,那就会产出很多printAction()函数对象,这也会短时间造成内存大量消耗,加上inline,上面的函数实际编译成如下:
fun main(){
println("inline fun")
println("hello")
}
这样就减少了函数对象的创建,节省的内存的消耗。
noinline
我们用inline定义函数之后,假如想让一些函数里的代码不直接移动到调用的地方,还是想像普通函数一样要咋办,就可以noinline 来修饰函数,不参加内联了:
inline fun test(noinline printAction:()->Unit){
println("inline fun")
printAction()
}
fun main(){
test{
println("hello")
}
}
实际编译成如下:
fun main(){
println("inline fun")
({
println("hello")
}).invoke()
}
crossinline
刚才讲的 noinline 是局部关闭内联优化,而这个crossinline,是局部加强内联优化。
//普通函数是不能直接return
private fun test1( printAction:()->Unit){
println("simple fun")
printAction()
}
//内联函数可以直接return
private inline fun test2(printAction:()->Unit){
println("inline fun")
printAction()
}
private inline fun test3(crossinline printAction:()->Unit){
println("crossinline fun")
printAction()
}
fun main(){
test1 {
println("fun1")
return //编译报错
}
test2 {
println("fun2")
return //编译正常
}
test3 {
println("fun3")
return //编译报错
}
}
crossinline 关键字就像一个契约,它用于保证内联函数的Lambda表达式中一定不会使用return全局返回,保证内联函数只能在最外层返回,而不能再别的地方放回,例如:
inline fun test4(func1: () -> Unit) {
runOnUiThread {
func1() //编译器报错
}
}
小结:
- kotlin只允许内联函数的函数参数内部有return,普通函数的函数参数内部不能有return
- crossinline让编译器帮我们检查函数参数内部是不是带有return,有的话直接在IDE提醒我们不能写(还是为了满足结论1,禁止函数参数写return)