探究Kotlin之第三部分

高阶函数

如果一个函数接收另一个函数作为参数,或者返回值的类型是另一个函数,那么称该函数为高阶函数。

fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
    val result = operation(num1, num2)
    return result
}

fun plus(num1: Int, num2: Int): Int {
    return num1 + num2
}

fun minus(num1: Int, num2: Int): Int {
    return num1 - num2
}

num1AndNum2是高阶函数,前两个参数是两个整型的数字,第三个参数是一个能接受两个整型数字并返回一个整型数据的函数,在函数内部,操作就是将前两个参数传给了第三个参数即operation函数。

之后又定义了两个函数,与operation相匹配。

使用如下:

    val a = 100
    val b = 20
    val result1 = num1AndNum2(a, b, ::plus)
    val result2 = num1AndNum2(a, b, ::minus)
    println("a+b=$result1")//120
    println("a-b=$result2")//80

这里的高阶函数第三个参数使用的是函数引用的方式,表示将plus() minus()两个函数作为参数传递进入高阶函数。

kotlin支持Lambda表达式来完成高阶函数的调用。

以上功能就可以修改为:

    val a = 100
    val b = 20
    val result1 = num1AndNum2(a, b){n1,n2->
        n1+n2
    }
    val result2 = num1AndNum2(a, b){n1,n2->
        n1-n2
    }
    println("a+b=$result1")
    println("a-b=$result2")  

这样就不需要额外定义与operation对应的函数了,直接在lambda表达式中写函数实现。

用高阶函数实现StringBuilder拼接功能

fun StringBuilder.build(block:StringBuilder.()->Unit):StringBuilder{
    block()
    return this
}

StringBuilder设置了一个build的扩展函数,这个扩展函数接收一个无返回值的block函数,整个高阶函数返回一个StringBuilder

在block函数的参数类型前加calssName.意思是规定了这个函数定义所在的类。方便我们调用build的时候传入的lambda表达式直接拥有StringBuilder的上下文。

内联函数

其实我们一直使用的lambda表达式,在底层被转换成了匿名类的实现方式。表明我们每调用一次;lambda表达式都会造成额外的性能和内存开销。为了解决这个问题,就提出使用内联函数,只需要在定义高阶函数时,在前面加上inline关键字。

使用内联函数时,kotlin编译器会将内联函数的代码在编译的时候自动替换到调用它的地方,保证不出现额外的开销。

但当我们接收两个或两个以上的函数类型的参数时,我们将高阶函数声明为内联,此时我们的需求是只与指定的函数参数内联,此时需要noinline关键字。

inline fun inlineTest(block1:()->Unit,noinline block2:()->Unit){
    //此时只有block1被内联
}

内联与非内联的区别:

  1. 内联的函数参数在编译的时候会被进行代码替换,他没有真正的参数属性。

    而非内联的函数参数可以自由传递给其他任何函数,他就是一个真正的参数。

    内敛的函数只允许传递给另一个内联函数。

  2. 内联函数所引用的lambda表达式可以return返回。

    非内联的函数参数所引用的lambda表达式只能局部返回。

另外,如果在高阶函数lambda表达式中调用了我们的传入的函数参数,此时我们又定义为内联函数,那么就会提示错误

此时需要借助crossinline关键字

inline fun runRunnable(crossinline block:()->Unit){
    Runnable{
        block()
    }.run()
}

crossinline关键字的原理是:
内联函数的lambda表达式允许使用return,而高阶函数匿名类中不允许使用return,二者产生冲突。crossinline关键字保证在内联函数的lambda表达式中一定不会使用return,冲突解决。

高阶函数应用之简化SharedPreference

  • kotlin正常使用方法:
	val editor=getSharedPreferences("data", Context.MODE_PRIVATE).edit()//获得Shredpreference.Editor对象
        editor.putInt("age",18)
        editor.putBoolean("sex",true)
        editor.apply()
  • 使用高阶函数简化:
fun SharedPreferences.opens(block:SharedPreferences.Editor.()->Unit){
    //opens方法直接拥有Sharedpreference的上下文,直接通过edit方法获取SharedPreferences.Editor对象
    val editor=edit()
    editor.block()
    editor.apply()
}

定义过高阶函数之后使用:

getSharedPreferences("data", Context.MODE_PRIVATE).opens {
            //因为block函数参数前的限定是SharedPreferences.Editor.,因此lambda表达式直接拥有它的上下文环境
            putBoolean("sex",true)
            putInt("age",18)
        }
  • 实际上KTX扩展库中已经包含该种用法,直接使用即可
getSharedPreferences("data", Context.MODE_PRIVATE).edit { 
    putInt("age",18)
    putBoolean("sex",false)
}

泛型

泛型类:

class MyClass<T>{
     fun myMethod(param:T):T{
         return param
     }
}
    var myClass = MyClass<Int>()
    val result = myClass.myMethod(100)

泛型方法:

class MyClass{
     fun <T>myMethod(param:T):T{
         return param
     }
}
    var myClass = MyClass()
    val result = myClass.myMethod<Int>(100)

由于kotlin优秀的类型推导机制,我们可以省略调用方法时的<Int>,传参时,自动推导

kotlin允许我们对泛型的类型进行限制,例如可以对myMethod方法的泛型可以设置上界

class MyClass{
     fun <T:Number>myMethod(param:T):T{
         return param
     }
}

若要让泛型的类型不可以为空,只需要将泛型的上界设置为Any

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值