android kotlin 高阶函数,Kotlin-高阶函数

函数是一个类型,就像编程语言中的基本类型一样,就像Java中的引用类型一样,函数是函数类型。基本类型、引用类型、函数类型,说白了物理空间就是内存的一段区域,逻辑空间叫什么基本类型、引用类型、函数类型。基本类型就是int, float这种存储数据的,引用类型就是类呗,一个类在内存中不也是一段区域嘛,函数类型就是一段操作流程呗,一段操作流程在内存中不也是一段区域嘛。总之一样啦。猫是动物,狗是动物,人家棕熊也是动物啦,都在地球上占据一定的空间,不能把人家当成空气。

android kotlin 高阶函数,Kotlin-高阶函数_第1张图片   

android kotlin 高阶函数,Kotlin-高阶函数_第2张图片  

android kotlin 高阶函数,Kotlin-高阶函数_第3张图片

既然他们都是一种类型,那就要同等对待,既可以作为变量,也可以作为常量;既可以作为函数形参,也可以作为函数返回值。猫和狗能结婚生子,人家棕熊也可以,不可以把人家阉割了。物物平等。

android kotlin 高阶函数,Kotlin-高阶函数_第4张图片

fun add(a: Int, b: Int) : Int {

return a + b

}

上面这个棕熊,哦,不对,函数,上面这个函数的类型是啥?

不知道吧,我告诉你,是这个:

(Int, Int) -> Int

惊不惊喜?咦,看不懂?回去补补lambda表达式去,老衲不负责给你补基础知识。哇咔咔!

好啦,既然函数有类型了,那我们用函数声明变量吧,它和用基本类型,用类声明变量是一样一样嘀。

var myfun : (Int, Int) -> Int //函数类型

var myBase : Float //基本类型

var myClass : String //引用类型

从此,江湖上出现了三剑客:基本类型、函数类型、引用类型。打遍天下无敌手。

定义完类型了,我得赋值啊,要不我定义类型干啥。

客官请看下面内容:

myfun = :: add //使用函数引用要用::,不能加(),因为加()就变成调用函数了,而不是使用函数引用

myBase = 1.5f

myClass = String("你瞅啥,我就喜欢用String的构造函数咋地") //实例化对象不需要用new了,直接用对象的构造函数

myClass = "当然,直接这样写也是可以的"

再来,函数类型作为形参:

fun sum(a: Int, b: Int, fn: (Int, Int) -> Int): Int {

return fn(a, b)

}

我就喜欢把函数类型传进去,咋嘀!

再来,函数类型作为返回值:

fun getMathFunc(type: String): (Int, Int)-> Int {

// 定义一个计算加法的局部函数

fun add(a: Int, b: Int) : Int {

return a + b;

}

// 定义一个计算减法的局部函数

fun sub(a: Int, b: Int) : Int {

return a - b;

}

// 定义一个计算乘法的局部函数

fun mul(a: Int, b: Int) : Int {

return a * b;

}

when(type) {

"add" -> return ::add

"sub" -> return ::sub

else -> return ::mul

}

}

fun main(args: Array) {

var mathFunc = getMathFunc("add") //得到add函数

println(mathFunc(5, 3)) //输出8

mathFunc = getMathFunc("sub") //得到sub函数

println(mathFunc(5, 3)) //输出2

mathFunc = getMathFunc("mul") //得到mul函数

println(mathFunc(5, 3)) //输出15

}

好啦,就说到这里吧,既然函数又能作为变量,又能作为形参,又能作为返回值,说不定还能作为常量(我猜测地,不过函数作为常量干啥,函数本身就是变化地,作为常量干啥,哈哈哈,完全没用,就像你把类实例化的对象作为常量干啥,也没用哇),那么函数这么厉害,和其他类型一样,就要给它和之前我们简单使用的函数做出区分,至少在名词上做出区分,这样才让人感觉高大上。记住,叫“高阶函数”!这个不重要,忘了也没事,别在意,就是个多余的名字嘛,之前的函数不被阉割掉,也不会出现这么个多余的名字。好吧,你可以这么理解,之前世界上的棕熊都是被阉割的,现在的棕熊才是正常的,和猫啊,狗啊一样,都能结婚生子。阿弥陀佛~~

我对自己是有要求嘀,是要求自己尽量写出更优雅的代码嘀,再来:

上面的局部函数太繁琐,替换成lambda表达式:

fun getMathFunc(type: String): (Int, Int)-> Int {

when(type) {

"add" -> return {a: Int, b: Int -> a + b}

"sub" -> return {a: Int, b: Int -> a - b}

else -> return {a: Int, b: Int -> a * b}

}

}

fun main(args: Array) {

var mathFunc = getMathFunc("add") //得到add函数

println(mathFunc(5, 3)) //输出8

mathFunc = getMathFunc("sub") //得到sub函数

println(mathFunc(5, 3)) //输出2

mathFunc = getMathFunc("mul") //得到mul函数

println(mathFunc(5, 3)) //输出15

}

另外,lambda表达式是可以根据上下文推断类型的,所以,我们还可以更简化,再来:

fun getMathFunc(type: String): (Int, Int)-> Int {

when(type) {

"add" -> return {a, b -> a + b}

"sub" -> return {a, b -> a - b}

else -> return {a, b -> a * b}

}

}

fun main(args: Array) {

var mathFunc = getMathFunc("add") //得到add函数

println(mathFunc(5, 3)) //输出8

mathFunc = getMathFunc("sub") //得到sub函数

println(mathFunc(5, 3)) //输出2

mathFunc = getMathFunc("mul") //得到mul函数

println(mathFunc(5, 3)) //输出15

}

终于可以OVER了~~~

且慢,谢谢颜文大神的指点,getMathFunc函数还可以使用“=”来赋值。

fun getMathFunc(type: String):(Int, Int) -> Int = when(type) {

"add" -> {a, b -> a + b}

"sub" -> {a, b -> a - b}

else -> {a, b -> a * b}

}

可以使用“=”赋值的有表达式和匿名函数,when语句可以这样写的话,我理解when语句应该是表达式吧?是吧?是吧?

查了下资料,果然如此。Kotlin中的if语句和when语句都可以作为表达式。

if语句作为if表达式时,这样写:

var str = if (age > 20) "age 大于20" else if(age < 20) "age小于20" else "age等于20"

when语句作为when表达式时,这样写:

var str = when (score) {

'A' -> {

println("望百尺竿头更进一步")

"优秀"

}

'B' -> "良好"

'C' -> "中"

'D' -> "及格"

else -> "不及格"

}

让我们再总结一下吧,表达式也可以给变量、常量赋值。

再让我们看下前面的例子吧,都哪些内容可以给变量赋值呢?

var myfun = :: add //使用函数引用要用::,不能加(),因为加()就变成调用函数了,而不是使用函数引用

var myBase = 1.5f

var myClass = String("你瞅啥,我就喜欢用String的构造函数咋地") //实例化对象不需要用new了,直接用对象的构造函数

// var myClass = "当然,直接这样写也是可以的"

var myExpression = if (age > 20) "age 大于20" else if(age < 20) "age小于20" else "age等于20" //表达式也可以直接赋值哦

相比于前面,又多个一种可以给变量赋值的,就是表达式。

再让我们从另一个角度考虑,既然变量声明可以用var表示,函数声明用fun表示,而所谓的声明,就是给起个名字而已,从栈中发出一个指针。变量var声明的指针可以指向常量、函数、对象、表达式,而函数fun声明的指针指向的只有函数么?不是的,函数声明的指针还可以指向表达式。细心的读者可以看到我前面的例子中,表达式也是可以给函数类型赋值的。

将if表达式赋给函数类型:

fun getMathFunc(age: Int):String = if (age > 20) "age大于20" else if(age < 20) "age小于20" else "age等于20"

fun main(args: Array) {

println(getMathFunc(25)) //输出“age大于20”

}

将when表达式赋给函数类型:

fun getMathFunc(type: String):(Int, Int) -> Int = when(type) {

"add" -> {a, b -> a + b}

"sub" -> {a, b -> a - b}

else -> {a, b -> a * b}

}

用表达式来给函数赋值也有一个名字,叫单表达式函数。

接着让我们再开一下脑洞,既然我前面说了基本类型、函数类型、类的引用类型都是一样一样的东东,那么表达式是否可以给类的引用类型赋值呢?

反正Java8中的lambda表达式是给函数式接口赋值的,不过那是因为Java8的lambda表达式不是纯函数,而是通过函数式接口实现的,所以对于Kotlin的表达式,在这方面也没有什么类比价值。

留给你去思考吧。欢迎留言讨论。

最后,让我们再想想,既然表达式能够赋值给变量,我们还赋值给函数干嘛?这不是多此一举嘛。

这个要从变量和函数的作用说起,函数是一段代码的封装,有传参用的形参和返回值,比如when表达式括号中的参数,可以是函数的形参传过来的。而如果赋值给变量的话,when表达式括号中的参数就必须在给该变量赋值之前指定。这完全是一种顺序化的代码执行逻辑,而不是函数调用逻辑。所以说,两者在功能上是不一样的。

请看下面代码:

//赋值给变量

var type = "add"

var mathFunc2:(Int, Int) -> Int = when(type) {

"add" -> {a, b -> a + b}

"sub" -> {a, b -> a - b}

else -> {a, b -> a * b}

}

//赋值给函数

fun getMathFunc(type: String):(Int, Int) -> Int = when(type) {

"add" -> {a, b -> a + b}

"sub" -> {a, b -> a - b}

else -> {a, b -> a * b}

}

fun main(args: Array) {

var mathFunc = getMathFunc("add") //得到add函数

println(mathFunc(5, 3)) //输出8

println(mathFunc2(5, 3)); // 输出8

}

就到这里吧。

android kotlin 高阶函数,Kotlin-高阶函数_第5张图片

你可能感兴趣的:(android,kotlin,高阶函数)