Kotlin学习笔记九-kotlin扩展函数与函数式编程

Kotlin学习笔记九

  • 扩展函数
    • 泛型扩展函数
    • 扩展属性
    • 可空类型的扩展函数
    • infix关键字
    • apply函数解析
  • 函数式编程
    • 变换
      • map
      • flatmap
    • 过滤与合并
      • 过滤函数 filter
      • 合并函数 zip
      • 合并函数 fold
      • 序列
      • 为什么要函数式编程?

扩展函数

扩展可以在不直接修改类定义的情况下增加类功能,扩展可以用于自定义类,也可以用于List,甚至安卓的TextView等类。

在实际项目目遇到就是扩展了viewBinding类的功能(获取输入框的值,绑定选择框等),使得对view的一些操作被剥离出去,多次被复用。减少了Activity里的逻辑。

可以给String 甚至Any扩展(运用于所有类)

// 扩展函数 swap,调换不同位置的值
fun MutableList.swap(index1: Int, index2: Int) {
    val tmp = this[index1]     //  this 对应该列表
    this[index1] = this[index2]
    this[index2] = tmp
}

默认所以文件有效(除非是用了),public.除非private ,本文件有效。
一般会把扩展函数放到一个文件里,加上命名空间 package,然后import使用。这样比较有条理,否则任何地方都可以使用的话,会比较乱。可以重命名扩展 。impirt as xxx

泛型扩展函数

泛型扩展函数的好处在于保留了原来类的特征,又给类加了扩展函数**。就是什么类都能用,还能保留类原有的特征,和超类的扩展相比,更加灵活**。如果一个扩展函数返回超类Any,那么即使使用这个函数返回一个String,也不能使用String的扩展函数,因为这个类此时被看作Any,不是String,向下转容易出事情。

我们的标准库函数,let,also,apply,就是泛型扩展函数。

扩展属性

主要是注意setter与getter,val没有setter。

var ExtensionTest.extensionParam: String
    set(value) {
        param1 = "param1$value"
        param1 = "param2$value"
    }
    get() = "$param1-$param2"

可空类型的扩展函数

可空类型上定义扩展函数,可以直接在扩展函数体内,解决可能出现的空值问题。一般在扩展函数体内配合?:使用。
eg

fun String?.printWithDefault(default:String)=print(this?:default)

infix关键字

省去括号 和 .。例如map里的里的to,就是使用了 infix
mapof(“ddd” to “ssss”)

infix  fun String?.printWithDefault(default:String)=print(this?:default)

//使用时
“ssss”  printWithDefault  "default"

apply函数解析

@kotlin.internal.InlineOnly
public inline fun  T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

为什么参数传的是 T.() -> Unit 而不是 () -> Unit

匿名函数也可以是扩展函数,这样匿名函数里就有这个对象(this),可以隐式调用了 。如果不用扩展函数,那么你传入的匿名函数,就和对象没有关系了,你无法在匿名函数体里,使用到对象的信息。

函数式编程

一个函数式应用通常由三大类函数构成:变换 transform,过滤 filter, 合并 combine。每类函数都是针对集合数据类型,产生一个结果。通过组合使用,可以构成复杂的计算行为。可以进行链式调用,就和我们之前使用的rxjava类似

变换

map

便利集合(例如list)的每一个元素,操作后返回一个改变后的新集合,但原来的集合没有改变
这个返回可以链式调用。链式调用可以省去很多很多中间变量的定义,所以简洁。

val   people:List=listof("ddd","ssss","aaa")
val  addPeople = people.map{it->
it+"add some  thing"
}

以后对集合的遍历,然后操作返回新的集合的话,就不用使用for循环了,可以使用map函数。

flatmap

操作集合的集合,将集合合并。

val result:List=listof(listof(1,2,3),listof(4,5,6)).flatmap{it}

过滤与合并

过滤函数 filter

val new lista=list.filter{true}

合并函数 zip

将两个集合合并,返回一个包含键值对集合,与flatmap不同。

val  key :List=listOf(“A”,“B”,“C”)
val  value:List=listOf(1,2,,3)
val all:Map=key.zip(value).toMap()

合并函数 fold

fold:遍历集合,实现累积计算

val fold:Int=list(1,2,3).fold(0){accumulator,number->
accumulator + number*3
}

序列

有规律的那啥,可以用while替代,但是用序列更方便,优雅。

list set map 早集合
kotlin还有惰性集合,sequence 按需产生,类似于惰性初始化,一般用于大量元素数据(大量数据时,会有性能差异,详见下方博客),甚至无限多(其实就是为了防止资源浪费)。

val numbers:Sequence =generateSequence(2){value->
value +1 

}.filter{ ... }
.take(1000)

list.take(1000),提取集合的前一千个元素
(1…5000)就是1到5000的一个集合,运算符重载
until也是一样效果

sequece 迭代器函数 ,惰性产生序列。它的take函数和集合类的take函数不是同一个。。sequece的take函数决定序列迭代多少次。

序列中的元素求值都是惰性的,所以可以更加高效使用序列来对数据集中的元素进行链式操作 (映射、过滤、变换等), 而不需要像普通集合那样,每进行一次数据操作,都必须要开辟新的内存来存储中间结果,而实际上绝大多数的数据集合操作的需求关注点在于最后的结果而不是中间的过程。

https://blog.csdn.net/PrisonJoker/article/details/114055543

为什么要函数式编程?

(1)累加变量都是隐式调用的,减少了许多的中间变量
(2)运算结果自动赋值给累加变量,减少出错的机会
(3)链式调用,新的任务函数也容易添加到任务链上,因为都兼容iterable类型

其实应用开发中,基本都是处理集合类的数据,所以这时,我们应该优先考虑用链式调用,用map,flatmap,zip这些现成的函数,尽可能的减少for循环的使用,那样容易出错。

你可能感兴趣的:(学习笔记,kotlin,学习,android)