kotlin从入门到看开|kotlin从入门到看开 ?

layout: post
title: "kotlin-高阶函数"
subtitle: "这个世界属于有天赋的人 也属于认真的人 更属于那些在有天赋的领域认真钻研的人"
高阶函数 高阶函数:传入或者返回函数的函数
函数引用的三种方式

  1. 包级函数作为高阶函数的参数的时候,直接按照参数返回值来判断是否合适.
  2. 类的成员函数(带有Receiver的函数)作为高阶函数的参数的时候,需要使用实例来进行引用.
  3. 扩展方法作为高阶函数的参数的时候,需要注意的是扩展方法有一个默认的参数就是实例本身
fun test() { val line = "-------" val arrayInt = listOf(11, 22, 33, 44, 55) var arrayStr = listOf("杏本诗歌", "守凪了子", "西宫结弦", "花畑佳子", "冈部伦太郎", "") /** * 包级函数 */ arrayInt.forEach(::println) println(line) /** * 类的成员函数 */ val pm = MyPrintln() arrayStr.filter { it.contains("子") }.forEach(pm::println) arrayStr.filter { it.length > 4 }.forEach(pm::println) println(line) /** * 扩展方法 */ arrayStr.filter(String::isNotBlank).forEach(::println) println(line) }

包级函数
map
  1. map:集合的映射
  2. map:集合的转换
val arrayInt1 = arrayInt.map { it * 4 } val arrayDouble = arrayInt.map(Int::toDouble) println(arrayInt1) println(arrayDouble)

flatMap
  1. flatMap:扁平化集合
  2. ... RangeTo
  3. 1..5:返回一个intRange(1,2,3,4,5)
val list = arrayListOf(1..9, 233..255, 79..88) val flatMap = list.flatMap { it } flatMap.forEach(::println)

reduce
  1. reduce通常用于求和
println(flatMap.reduce(Int::plus)) println(flatMap.reduce { acc, i -> acc + i }) //阶乘示例 println(factorial(8))

阶乘
/** * 阶乘 */ private fun factorial(n: Int): Int { if (n == 0) return 1 return (1..n).reduce { acc, i -> acc * i } }

flod
  1. fold:对集合进行自定义计算
println((0..1).fold(8) { acc, i -> acc + i })/** * joinToString:对集合进行转化和拼接 */ println((0..10).joinToString(",")) val fold = (0..5).fold(StringBuilder()) { acc, i -> acc.append(i).append(",") } println(fold)

字符串拼接
println((0..10).joinToString(","))

filter
  1. filter用于过滤,传入表达式的值为true时保留:
val pm = MyPrintln() arrayStr.filter { it.contains("子") }.forEach(pm::println) arrayStr.filter { it.length > 4 }.forEach(pm::println)

takeWhile
  1. takeWhile通常用于带有条件的循环遍历,直到第一个不满足条件元素出现循环结束.
//直到第一个不小于44的元素出现,循环结束. //最后输出元素应为(11,22,33) val arrayInt = listOf(11, 22, 33, 44, 55) arrayInt.takeWhile { it<44 }.forEach(::println)

补充说明

  • 包级函数:在包内直接声明函数的方式叫作包级函数
package com.litton.ishirinline fun print(message: Int) { System.out.println(message) }

data class
data class singer(var name: String, var song: String) { fun sing() { println("$name,演唱新单曲$song") } }

let
  • let: it表示引用对象,可调用其成员(属性以及方法),it不可省略.
  • 返回值: 返回值为函数块的最后一行,为空就返回一个Unit类型的默认值.
使用:
KaryNg.let {}//在函数体内使用it替代引用对象去访问其公有的属性和方法 KaryNg?.let {}//另一种用途:?判断对象是否为空,不为空才会执行let函数体

例子:
fun main(args: Array) { val KaryNg = singer("吴雨霏", "我本人") val kary: Any = KaryNg?.let { it.song it.name.length } println(kary) }

输出:
singer(name=吴雨霏, song= <<我本人>>)
3
适用场景:
使用let函数处理需要针对一个可null的对象统一做判空处理.
官方源码:
/** * Calls the specified function [block] with `this` value as its argument and returns its result. */ @kotlin.internal.InlineOnly public inline fun T.let(block: (T) -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block(this) }

also
  • also: it表示引用对象,可调用其成员(属性以及方法),it不可省略.
  • 返回值: 返回值为函数块的最后一行,为空就返回一个Unit类型的默认值.
使用:
also函数结构实际上和let很像唯一的区别就是返回值不一样,let以闭包的形式返回,返回函数体内最后一行的值,如果最后一行为空就返回一个Unit类型的默认值.而also函数则返回传入对象本身.
KaryNg.run {}

例子:
fun main(args: Array) { val KaryNg = singer("吴雨霏", "我本人") val kary: Any = KaryNg?. also { it.song it.name.length } println(kary) }

输出:
吴雨霏,演唱新单曲 <<我本人>>

singer(name=吴雨霏, song= <<我本人>>)
适用场景:
一般可用于多个扩展函数链式调用
官方源码:
/** * Calls the specified function [block] with `this` value as its argument and returns `this` value. */ @kotlin.internal.InlineOnly @SinceKotlin("1.1") public inline fun T.also(block: (T) -> Unit): T { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } block(this) return this }

with
  • with: 在函数块内通过 this 指代对象,调用成员(属性以及方法),this可省略.
  • 返回值: 返回值为函数块的最后一行,为空就返回一个Unit类型的默认值.
使用:
with函数和前面的函数使用方式略有不同,它不是以扩展函数.它将对象作为函数的参数
with(KaryNg){ sing() }

例子:
fun main(args: Array) { val KaryNg = singer("吴雨霏", "我本人") val sing=with(KaryNg){ println(this) sing() name } println(sing) }

输出:
singer(name=吴雨霏, song= <<我本人>>)

吴雨霏,演唱新单曲 <<我本人>>

吴雨霏
适用场景:
【kotlin从入门到看开|kotlin从入门到看开 ?】适用于调用同一个类的多个方法时,可以省去类名重复,直接调用类方法即可,经常用于Android中RecyclerView中onBinderViewHolder中,数据model的属性映射到UI上
官方源码:
/** * Calls the specified function [block] with the given [receiver] as its receiver and returns its result. */ @kotlin.internal.InlineOnly public inline fun with(receiver: T, block: T.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return receiver.block() }

run
  • run: 在函数块内通过 this 指代对象,调用成员(属性以及方法),this可省略.
  • 返回值: 返回值为函数块的最后一行,为空就返回一个Unit类型的默认值.
使用:
KaryNg.run {}

例子:
fun main(args: Array) { val KaryNg = singer("吴雨霏", "我本人") val kary: Any = KaryNg.run { println(this) sing() name.length } println(kary) }

输出:
singer(name=吴雨霏, song= <<我本人>>)

吴雨霏,演唱新单曲 <<我本人>>

3
适用场景:
适用于let,with函数任何场景.run函数是let,with两个函数结合体,准确来说它弥补了let函数在函数体内必须使用it参数替代对象,在run函数中可以像with函数一样可以省略,直接访问实例的公有属性和方法,另一方面它弥补了with函数传入对象判空问题,在run函数中可以像let函数一样做判空处理
官方源码:
/** * Calls the specified function [block] with `this` value as its receiver and returns its result. */ @kotlin.internal.InlineOnly public inline fun T.run(block: T.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block() }

apply
  • with: 在函数块内通过 this 指代对象,调用成员(属性以及方法),this可省略.
  • 返回值: 返回值为函数块的最后一行,为空就返回一个Unit类型的默认值.
使用:
从结构上来看apply函数和run函数很像,唯一不同就是它们返回值不一样,run函数以闭包形式返回最后一行代码的值,而apply函数的返回传入对象本身
KaryNg.apply {}

例子
fun main(args: Array) { val KaryNg = singer("吴雨霏", "我本人") val kary: Any = KaryNg.apply { song sing() } println(kary) }

输出
吴雨霏,演唱新单曲我本人

singer(name=吴雨霏, song=我本人)
适用场景:
apply一般用于一个对象实例初始化的时候,需要对对象中的属性进行赋值.或者动态inflate出一个XML的View的时候需要给View绑定数据也会用到,这种情景非常常见.特别是在我们开发中会有一些数据model向View model转化实例化的过程中需要用到.
官方源码
/** * Calls the specified function [block] with `this` value as its receiver and returns `this` value. */ @kotlin.internal.InlineOnly public inline fun T.apply(block: T.() -> Unit): T { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } block() return this }

use
未完结
  • use: 在函数块内通过 it 指代对象,调用成员(属性以及方法),it不可省略.
  • 返回值: 返回值为函数块的最后一行,为空就返回一个Unit类型的默认值.
例子
val read = BufferedReader(FileReader("build.gradle")).use { val readText = it.readLine() readText } println(read)

输出
apply plugin: 'com.android.application'
适用场景:
use自己关流.
官方源码
/** * Executes the given [block] function on this resource and then closes it down correctly whether an exception * is thrown or not. * * @param block a function to process this [Closeable] resource. * @return the result of [block] function invoked on this resource. */ @InlineOnly @RequireKotlin("1.2", versionKind = RequireKotlinVersionKind.COMPILER_VERSION, message = "Requires newer compiler version to be inlined correctly.") public inline fun T.use(block: (T) -> R): R { var exception: Throwable? = null try { return block(this) } catch (e: Throwable) { exception = e throw e } finally { when { apiVersionIsAtLeast(1, 1, 0) -> this.closeFinally(exception) this == null -> {} exception == null -> close() else -> try { close() } catch (closeException: Throwable) { // cause.addSuppressed(closeException) // ignored here } } } }

闭包
  1. 函数运行的环境
  2. 持有函数运行状态
  3. 函数内部可以定义函数
  4. 函数内部也可以定义类
复合函数
m(x) = f(g(x))
  • g = g(x) P1:即g函数的参数{x} P2:即g函数的返回值{g}== P2
  • f = f(g) P2:即f函数的参数{g}== P2 R:即f函数的返回值{f}== R
  • m = m(x) P1:即g函数的参数{x}
fun onTest() { //m(x) = f(g(x)) val g = { i: Int -> i + 7 } //g(x) = x+7 val f = { i: Int -> i * 2 } //f(g) = g*2 val m = g composite f //m(x) = (x+7)*2 val m1 = f composite g //m(x) = (x*2)+7 val value = https://www.it610.com/article/m(2) val value1 = m1(2) println(value) println(value1) }/** * @param P1 * @param P2 * @param R */ infix fun Function1.composite(function: Function1): Function1 { return fun(p1: P1): R { return function.invoke(this.invoke(p1)) } }

柯里化
多元函数变换成一元函数调用链
fun log(tag: String) = fun(target: OutputStream) = fun(message: Any) = target.write("$tag-$message\n".toByteArray()) fun log1(tag:String,target:OutputStream,message: Any){ target.write("$tag-$message \n".toByteArray()) } fun main(args: Array) { log("日志")(System.out)("记录日志1") ::log1.curried()("日志")(System.out)("记录日志2") } fun Function3.curried() = fun(p1: P1) = fun(p2: P2) = fun(p3: P3) = this(p1, p2, p3)

偏函数
传入部分参数得到新函数

    推荐阅读