Kotlin-知识分享-1--探索高阶函数

本文介绍了高阶函数的概念和在Kotlin中的应用,包括将函数作为参数传递、返回函数以及内联函数和Lambda表达式的使用。通过示例展示了Kotlin中声明和使用Lambda表达式的方式,如无返回值函数、有返回值函数、拓展函数等,并讨论了内联函数对性能的影响。此外,还提到了Kotlin中类型推导和参数处理的细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

高阶函数是现代编程语言中一个重要的概念。它们不仅在函数式编程中扮演着关键角色,也被广泛应用于其他编程范式。高阶函数的核心思想是将函数作为参数传递给其他函数或从函数中返回另一个函数。通过这种方式,高阶函数使得代码更加模块化,可复用性更强,并且可以极大地提升代码的可读性和简洁性。本文将介绍高阶函数的基础概念、优点以及如何在不同场景下使用它们。无论你是一名有经验的程序员还是初学者,都能从本文中获得有益的知识,进一步提高自己的编程技能。

Kotlin-lamda与高阶函数

Kotlin函数先有输入后有输出

//java代码先有输出再有输入
public Object getStudent(String name) {
   ...
}
//kotlin代码现有输入再有输出
public fun getStudent(name:String):Any {
 	...
}

Kotlin函数声明

声明一个无返回的kotlin函数

//声明一个函数,()->Unit相当于java中的void声明
//类似c++中的头文件的感受,需要对应的实现
var method : ()->Unit 

var method2 : (Int,Int)->Unit

var method3 : (String,Double) -> Any

对应的java实现

public void method() {
	...
}

public void method2(int a,int b){
	...
}

public Object method3(String a,double b) {
	...
}

更进一步的声明

直接实现,类型kotlin可以根据类型推导确定

//匿名函数
var method01 = { println("我是method01函数") }

//等价于
var method01 : ()->Unit = { println("我是method01函数") }

对应的java实现

public void method01() {
	System.out.println("我是method01函数")
}

有返回值的方法声明

var method02 = { "I'm method02"}

equels

public String method02(){
	return "I'm method01";
}

字符串模板

var method03 = {str:String -> println("this is $str")

equels

public void method03(String str) {
	System.out.println("this is " + str); 
}

另外一种声明

var method04 = {num1:Int,num2:Int - >num1.toString() + num2.toString()}

equels

public String method4(int num1,int num2){
	retrun String.valueof(num1) + String.valueof(num2);
}

先声明后实现

var method06 :(Int) -> String
method06 = fun(value /*:Int*/)/*String*/ = value.toString

也可以声明时实现

var method7:(Int)->String = { a /*:String*/ -> "$a"}
//equels 
//"it" is automatic generation of system
var method7:(Int)->String = {/*it ->*/ "$a"}

如果有参数没有使用
_拒收

var method08 :(Int,Int)->Unit  = { _,b->
	print("the second para is $b")
}

java三元运算符kolin替代

var method09 = {sex:Char ->if(sex == 'male') print("it's male") else print("it's female")

复写

var method10 = {number:Int -> println("this is $number")}
//复写不能改变其类型
method10 = {println("is it $it?")}

Kotlin中的拓展函数

给String添加拓展函数,这也是Compose的实现方式,关于这点可参考为 Kotlin 的函数添加作用域限制(以 Compose 为例)

     var method11: String.() -> Unit = {
        //this指的是String对象本身
        println(this)
    }

如果给Any类型添加拓展函数,可以给作为默认的函数拓展,拓展函数可以传入参数,可以使用invoke调用,第一个参数为自身

Lamda表达式和普通函数的区别

lamda表达式最后一行为返回值
例如

    var methodK02/*: (Int) -> Int*/ = { a: Int -> a + 1 }

函数体没有return无法进行类型推导

    fun k02(a: Int)/*:Unit*/ {
        val b = a + 1
        b
    }
	fun k03(a: Int):Int {
        val b = a + 1
        return b
    }

高阶函数

函数 -> (para->Unit),即函数中的函数

举例 run函数

	//返回类型为Unit
    var method12 = kotlin.run { println("this is a code") }


	@kotlin.internal.InlineOnly
	public inline fun <R> run(block: () -> R): R {
    	contract {
        	callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    	}
    	return block()
	}

run函数是一个内联函数
在 Kotlin 中,inline 是一个关键字,用于声明内联函数。使用 inline 修饰符可以通过将函数的代码插入调用处来减少函数调用的开销。这样可以提高程序的执行效率,并避免过多的函数调用带来的性能损失。

常见的内联函数包括高阶函数和 Lambda 表达式,它们在编译时会被转换为匿名类或对象,这些类或对象的实例在运行时创建。当使用这些函数时,编译器会创建一个匿名类或对象的实例来代表这些函数,并在运行时进行调用。但是,使用 inline 关键字修饰的函数将会在编译时被直接复制到调用处,而不是生成匿名类或对象。这样可以避免对象分配和函数调用的开销,从而提高程序的执行效率,并减少内存的使用。因此,内联函数可以消除这些额外的对象分配和函数调用的开销。

需要注意的是,虽然内联函数能够消除对象分配和函数调用的开销,但在某些情况下也可能会带来一些副作用。例如,在使用大量的内联函数时,可能会使编译后的代码变得更大,从而增加应用程序的安装包大小。

	//类型为String -> Unit
    fun k01() = { n1: String ->
        println(n1)
    }
fun main(args: Array<String>) {
    println("Hello World!")

    // Try adding program arguments via Run/Debug configuration.
    // Learn more about running applications: https://www.jetbrains.com/help/idea/running-applications.html.
    println("Program arguments: ${args.joinToString()}")

    val test = StringExtra()

    test.method12
    //简易调用
    test.k01()("123")
}

说到简易调用,可以额外举一个例子

	var method21: Double.(Double, Double) -> Unit = { a, b -> println("the result is ${this + a + b}") }
    println(method21.invoke(55.5, 6.6, 777.7))
    55.5.method21(6.0, 8.8)

关于Kolin中Float和Double的类型推导需要注意,Kotlin中小数默认均为Double,只有加f才能声明为Float类型,不过默认使用 Double 能省很多麻烦。除非特殊需要,尽量不要指定为 Float。

    val a/*:Double*/ = 6.0
    val b/*:Float*/ = 6.0f

这是调用时反编译的代码

fun aa(){}和fun aa2() ={}的区别
第一个为一个函数
第二个接受一个匿名函数,
共同点,执行现象是一样的。

	fun aa(){}
   	fun aa2()/*: () -> Int*/ =  { 1 }


    var aa3 = aa2()
    var aa4 = ::aa
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值