在kotlin中我们将函数作为参数或者返回值的函数叫做高阶函数,也就是使用方法体作为参数的方法叫做高阶方法。
-
函数作为参数
我们通过一个实战来了解它的定义
实战:需求-----实现一个可以对集合元素进行求和的高阶函数,并且每遍历一个元素都要有回调。
fun List<Int>.sum(callback:(Int) ->Unit):Int{
var result=0
for (v in this){
result+=v
callback(v)
}
return result
}
这个方法用到了扩展,直接使用List的扩展创建方法,在方法内部使用this关键字访问该集合,关于扩展可能有很多兄弟不清楚,所以我列出了它不用扩展的方法,如下:
fun test6(list: List<Int>,callback: (Int) -> Unit):Int{
var result=0
for (v in list){
result+=v
callback(v)
}
return result
}
方法中的第二个参数是一个回调,callback: (Int) -> Unit这句代码表示返回一个int型数据,Unit表示默认返回为空。再来看一下它的调用。
val list = listOf(1, 2, 3, 4)
val sum = test6(list,{
println(it)
} )
println(sum)
这里我分别打印了这个集合的每一项和所有元素的和,我们可以看到在第二个参数的地方我们实现了callback函数,所以test6方法的第二个参数是callback方法,callback方法等同于
fun callback(it:Int){
println(it)
}
这就是将函数作为参数的高阶函数。
-
函数作为返回值
同样的先来做一个小实战
需求-----实现一个高阶函数,并且返回一个声明为(scale:Int)->Float的函数,返回的函数可以求取集合元素所有和的scale倍。
注:scale:Int)->Float的意思可以用lambda来理解:该函数接收一个scale的Int型参数,返回一个Float的参数。
fun test7(list: List<Int>): (scale: Int) -> Float {
println("这是方法的第一层")
return fun(scale): Float {
var result = 0F
for (v in list) {
result += v * scale
}
return result
}
}
调用:
val list = listOf(1, 2, 3, 4)
val result=test7(list)(2)
println(result)
注意调用的格式就好了,第二个(2)是表示向返回的函数传递的参数,其实可以理解为它是一个两层函数,调用时第一个括号(list)表示向test7方法传递list参数,第二个括号(2)表示向test7的返回函数传递参数2.
-
方法中的闭包(closure)
闭包可以理解为能够读取其他方法内部变量的方法,所以说闭包是将方法内部与方法外部连接起来的桥梁。
闭包的特性
- 方法可以作为另一个方法的返回值或参数,还可以作为一个变量的值。
- 方法可以嵌套定义,即在一个方法内部可以定义另一个方法。
闭包的好处: - 加强模块化
- 抽象
- 灵活
- 简化代码
说再多也没用,来个实战。
实战:
◆需求:实现一个testClosure方法 ,该方法要接收一个Int类型的v1参数,同时能够返回一个声明为(v2: Int, (Int)-> Unit)的函数,并且这个函数能够计算v1与v2的和。
fun testClosure(v1:Int):(v2:Int,(Int)->Unit)->Unit{
return fun (v2:Int,printer:(Int)->Unit){
printer(v1+v2)
}
}
调用
testClosure(2)(3){
println(it)
}
这个例子有点复杂,要用心去理解一下,这个testClosure()接收一个参数v1,它的返回值类型是一个函数,我们暂时把它叫做f1,f1的构造是v2:Int,(Int)->Unit)这样的,表示f1接收两个参数,第一个参数是一个int型数据v2,第二个参数暂时叫做f2,f1没有返回值,f2是返回一个int型数据,后面加Unit让它暂时返回为空,最后一个Unit是表示整个testClosure()方法暂时返回为空。
调用时第一个参数2是传递给方法testClosure()的参数v1,第二哥参数3是传递给函数f1的参数v2,it表示f2返回的值。
上面这个例子是函数作为参数和返回值的一个复杂嵌套使用,要配合lambda表达式来理解。
-
Kotlin数据类的解构
这是一个解析数据的小技巧,刚好用到就在这里分享一下,用完你就知道kotlin有多好了。
data class Result(var message:String,var code:Int)
fun test0(){
var result1=Result("成功",1)
var (msg,code)=result1
println("message:$msg code:$code")
}
仅作为分享,不多解释,平时接收后台接口数据可以用这种方式反解拿到接口中的某项数据。
-
方法的字面值
将方法定义为变量,可以作为变量去调用;
fun test11(){
var temp: ((Int) -> Boolean)? =null
temp={num ->(num>10)}
println(temp(11))
}
仅作为学习记录,大家好好看前面的内容这里应该不难理解。
-
kotlin中的构造方法
kotlin在构造方法方面也比Java要方便许多,我们先来看最基本的构造方法怎么写:
class KotlinClass (name:String){
}
kotlin中类的构造方法可以直接在类的声明时创建参数,比如上面例子就是直接实现了类KotlinClass 的主构造方法,该构造方法接收一个String类型的参数name,那我们都知道类的构造方法可以有多个,怎么声明多个构造方法呢?
可以在类的内部声明多个构造方法,上面例子的叫做主构造方法,类中声明的都叫次构造方法,次构造方法在声明时都要调用主构造方法。
class KotlinClass (name:String){
constructor(age:Int,name: String):this(name){
println("name:$name")
}
constructor(age: Int,name: String,phone:Long):this(name){
println("phone:$phone")
}
}
如上所示,我们在类的内部定义了两个次构造方法,都通过this关键字调用了它的主构造方法。
下面是对每个构造方法的调用:
/*调用类的主构造方法*/
var name="zzp"
KotlinClass(name)
/*调用类的第一个次构造方法*/
KotlinClass(20,"zzp")
/*调用类的第二个次构造方法*/
KotlinClass(20,"zzp",110)
kotlin的构造方法大致如上所示,接下来我说一点在开发中经常会用到的,上面的例子以主构造方法为例,我们可以在主构造方法传入一个name的字符串,假如我们需要在类里面的某个方法操作这个name,怎么拿到它呢?按照Java的办法也可以拿到,代码如下:
var name1:String=""
constructor(age: Int, name: String) : this(name) {
name1=name
println("name:$name")
}
我们需要再定义一个变量name1,在构造方法中将构造方法的参数name赋值给name1,这样才能拿到构造方法的参数,kotlin还有一个更简单的方法,在构造方法参数列表就对该参数进行声明。
class KotlinClass(val name: String) {
fun println(){
println(name)
}
}
在参数前面加了个val声明name,然后就可以直接在下面的方法体内直接调用name变量。这也算是一个小技巧了。当然不加var/val也是可以直接使用构造方法参数的,就要用到初始代码块init了
init {
println(name)
}
这样也是可以的,我们只需要把所有方法在init内部调用就可以了。
-
kotlin继承如何写子类构造方法
这个非常简单,只需要记住一点,子类的构造方法必须先调用父类构造方法,这点和Java是一样的,还不清楚继承的可以先看我的另一篇文章Java-----继承
open class Animal(val age: Int)
class Dog(age: Int) :Animal(age)
如上所示,kotlin继承使用冒号,在后面跟上父类构造方法就可以了。父类需要用open关键字修饰才能被继承,类似于Java的public。
扩展:kotlin继承子类如何重写父类构造方法、如何覆盖父类成员变量
open class Animal(val age: Int) {
open var foot: Int = 0
open fun printM(){
println("动物有很多脚")
}
}
class Dog(age: Int) : Animal(age) {
//覆盖父类成员对象
override var foot=4
//重写父类成员方法
override fun printM(){
println("狗有四只脚")
}
}
重写父类的成员方法或者覆盖它的成员变量都需要先使用open关键字将父类的成员变量和成员方法打开,在子类中重写时加上override修饰。
网友评论