Kotlin基础 Kotlin语言声明变量与内置数据类型 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 fun main () { println("Hello World" ) var name: String = "Derry" name = "Lance" println(name) }
Kotlin语言的只读变量 代码:
1 2 3 4 5 6 fun main () { val info :String ="MyInfo" println(info) }
Kotlin语言的类型判断 代码:
1 2 3 4 5 6 7 8 9 10 fun main () { val info :String = "Derry is Success" println(info) val age = 98 println(age) }
Kotlin语言的编译时常量 代码:
1 2 3 4 5 6 const val PI=3.14 fun main () { }
查看kotlin反编译字节码 代码:
1 2 3 4 5 6 7 8 9 10 const val PI1 = 3.1415 const val PI2 = 3.1415 const val age = 99 fun main () { val name = "Derry" val sex = '男' val number = 108 }
Tools->Kotlin->Show Kotlin Bytecode
kotlin引用类型学习 1 2 3 4 5 6 7 fun main () { val age: Int = 99 val pi: Float = 3.1415f val pi2: Double = 3.1415 val isOk: Boolean = true }
range表达式 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 fun main () { val number = 148 if (number in 10. .59 ) { println("不及格" ) } else if (number in 0. .9 ) { println("建议remake" ) } else if (number in 60. .100 ) { println("及格" ) } else if (number !in 0. .100 ) { println("不正确" ) } }
when表达式 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 fun main () { val week = 5 val info = when (week) { 1 -> "星期一" 2 -> "星期二" 3 -> "星期三" 4 -> "星期四" 5 -> "星期五" 6 -> "星期六" 7 -> "星期天" else -> "错误天数" } println(info) }
String模版 代码:
1 2 3 4 5 6 7 8 9 fun main () { val garden = "黄石公园" val time = 6 println("今天天气很晴朗,去${garden} 玩,玩了$time 小时" ) val isLogin = true println("server response result: ${if (isLogin) "恭喜你登录成功" else "登录失败" } " ) }
kotlin语言函数头学习 代码:
1 2 3 4 5 6 7 8 9 fun main () { method01(99 ,"张三" ) } private fun method01 (age:Int ,name:String ) :Int { println("你的姓名是$name ,你的年龄是$age " ) return 200 }
kotlin函数参数的默认参数 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 fun main () { method01("张三" , 99 ) method02("李四" ) method03() method03("赵六" ,89 ) } private fun method01 (name: String , age: Int ) : Int { println("你的姓名是$name ,你的年龄是$age " ) return 200 } private fun method02 (name: String , age: Int = 18 ) : Int { println("你的姓名是$name ,你的年龄是$age " ) return 200 } private fun method03 (name: String ="王五" , age: Int = 18 ) : Int { println("你的姓名是$name ,你的年龄是$age " ) return 200 }
kotlin语言的具名函数参数 代码:
1 2 3 4 5 6 7 8 fun main () { loginAction(age = 99 ,userPassword = "123" ,userName = "张三" ,phoneNumber = "123456" ) } private fun loginAction (userName:String ,userPassword:String ,phoneNumber:String ,age:Int ) { println("userName:$userName ,userPassword:$userPassword ,phoneNumber:$phoneNumber ,age:$age " ) }
kotlin语言Unit函数特点 代码:
1 2 3 4 5 6 7 8 9 10 11 12 private fun doWork () : Unit { return println() } private fun doWork1 () { return println() } private fun doWork2 () { println() }
上面三个是等效的
kotlin语言的Nothing类型特点 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 fun main () { show(99 ) } private fun show (number: Int ) { when (number) { -1 -> TODO("没有该分数" ) in 0. .59 -> println("不及格" ) in 60. .70 -> println("一般" ) in 71. .80 -> println("良好" ) in 81. .100 -> println("优秀" ) } } interface A { fun show () } class AImpl :A { override fun show () { TODO("Not yet implemented" ) } }
kotlin语言的反引号中函数名特点 代码:
1 2 3 4 5 6 7 8 9 10 11 fun main () { `登录功能 2022 年1 月22 号`("张三" ,"123456" ) } private fun `登录功能 2022年1月22号`(name:String ,pwd:String ) { println("测试:姓名:" +name+" 密码:" +pwd) } private fun `7626837269`() { }
匿名函数 代码:
1 2 3 4 5 6 7 8 fun main () { val len = "Jack" .count() println(len) val count = "Jack" .count() { it == 'c' } println(count) }
函数类型和隐式返回 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 fun main () { val methodAction: () -> String methodAction = { val inputValue = 999999 "$inputValue Jack" } println(methodAction()) }
函数参数 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 fun main () { val methAction: (Int , Int , Int ) -> String = { number1, number2, number3 -> val inputValue = 999999 "$inputValue Jack 参数1:$number1 ,参数2$number2 ,参数3:$number3 " } println(methAction(1 ,2 ,3 )) }
it关键字特点 1 2 3 4 5 6 7 8 9 10 11 12 13 fun main () { val methodAction :(Int ,Int ,Int )->String ={ n1,n2,n3-> val number =673 ; println("$number n1:$n1 ,n2:$n2 ,n3:$n3 " ) "$number n1:$n1 ,n2:$n2 ,n3:$n3 " } methodAction(1 ,2 ,3 ) val methodAction2:(String)->String={"$it xxx" } println(methodAction2("AAAA" )) val methodAction3:(Double )->String ={"$it xxx" } println(methodAction3(678.67 )) }
匿名函数的类型推断 1 2 3 4 5 6 7 8 9 fun main () { val method1={v1:Double ,v2:Float ,v3:Int -> "v1:$v1 ,v2:$v2 ,v3:$v3 " } println(method1(5687.78 , 798.3f , 909 )) }
lambda学习 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 fun main () { val addResultMethod = { number1: Int , number2: Int -> "俩数相加的结果是:${number1 + number2} " } println(addResultMethod(1 , 1 )) val weekResultMethod={number:Int -> when (number){ 1 ->"星期一" 2 ->"星期二" 3 ->"星期三" 4 ->"星期四" 5 ->"星期五" 6 ->"星期六" 7 ->"星期天" else ->-1 } } println(weekResultMethod(2 )) }
在函数中定义参数是函数的函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 fun main () { loginAPI("admin" , "12345" ) { msg: String, code: Int -> println("最终登录情况:msg:$msg ,code:$code " ) } } const val USER_NAME_SAVE_DB = "admin" const val USER_PWD_SAVE_DB = "12345" fun loginAPI (username: String , userpwd: String , responseResult: (String , Int ) -> Unit ) { if (username == null || userpwd == null ) { TODO("用户名或密码为空" ) } if (username.length > 3 && userpwd.length > 3 ) { if (webServiceLoginAPI(username, userpwd)) { responseResult("login success" , 200 ) } else { responseResult("login error" , 404 ) } } else { TODO("用户名和密码不合格" ) } } private fun webServiceLoginAPI (name: String , pwd: String ) : Boolean { return name == USER_NAME_SAVE_DB && pwd == USER_PWD_SAVE_DB }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 fun main () { loginAPI2("admin" , "12345" , { msg: String, code: Int -> println("最终登录情况:msg:$msg ,code:$code " ) }) loginAPI2("admin" , "12345" , responseResult = { msg: String, code: Int -> println("最终登录情况:msg:$msg ,code:$code " ) }) loginAPI2("admin" , "12345" ) { msg: String, code: Int -> println("最终登录情况:msg:$msg ,code:$code " ) } } const val USER_NAME_SAVE_DB2 = "admin" const val USER_PWD_SAVE_DB2 = "12345" fun loginAPI2 (username: String , userpwd: String , responseResult: (String , Int ) -> Unit ) { if (username == null || userpwd == null ) { TODO("用户名或密码为空" ) } if (username.length > 3 && userpwd.length > 3 ) { if (webServiceLoginAPI(username, userpwd)) { responseResult("login success" , 200 ) } else { responseResult("login error" , 404 ) } } else { TODO("用户名和密码不合格" ) } } private fun webServiceLoginAPI (name: String , pwd: String ) : Boolean { return name == USER_NAME_SAVE_DB2 && pwd == USER_PWD_SAVE_DB2 }
kotlin语言的函数内联 函数中使用lambda就应该使用内联 inline关键字,若函数没用使用lambda,就不需要声明成内联
如果此函数不使用内联,在调用端会生成多个对象来完成lambda的调用(性能损耗)
使用内联相当于C++ 中 #define 宏定义 宏替换 会把代码替换到调用处,调用处没有任何函数开辟,对象开辟的损耗
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package derry.s1fun main () { loginAPI3("admin" , "12345" ) { msg: String, code: Int -> println("最终登录情况:msg:$msg ,code:$code " ) } } const val USER_NAME_SAVE_DB3 = "admin" const val USER_PWD_SAVE_DB3 = "12345" inline fun loginAPI3 (username: String , userpwd: String , responseResult: (String , Int ) -> Unit ) { if (username == null || userpwd == null ) { TODO("用户名或密码为空" ) } if (username.length > 3 && userpwd.length > 3 ) { if (webServiceLoginAPI3(username, userpwd)) { responseResult("login success" , 200 ) } else { responseResult("login error" , 404 ) } } else { TODO("用户名和密码不合格" ) } } fun webServiceLoginAPI3 (name: String , pwd: String ) : Boolean { return name == USER_NAME_SAVE_DB3 && pwd == USER_PWD_SAVE_DB3 }
函数引用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 fun main () { val obj = ::methodResponseResult val obj1 = obj val obj2 =obj1 login("admin" ,"12345" ,obj2) } fun methodResponseResult (msg: String , code: Int ) { println("最终登录情况:msg:$msg ,code:$code " ) } const val USER_NAME_SAVE_DB4 = "admin" const val USER_PWD_SAVE_DB4 = "12345" inline fun login (name: String , pwd: String , responseResult: (String , Int ) -> Unit ) { if (USER_NAME_SAVE_DB4 == name && USER_PWD_SAVE_DB4 == pwd) { responseResult("login success" , 200 ) } else { responseResult("login error" , 404 ) } }
函数类型作为返回类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 fun main () { val r = show("kotlin" ) val showMethod_niming = showMethod("show" ) println(showMethod_niming("程序员" ,38 )) } fun show (info:String ) :Boolean { println("我是show函数 info:$info " ) return true } fun show2 (info:String ) :String{ println("我是show函数 info:$info " ) return "XXX" } fun showMethod (info:String ) :(String,Int )->String{ println("我是show函数 info:$info " ) return {name:String,age:Int -> "匿名函数 name:$name , age:$age " } }
匿名函数与具名函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 fun main () { showPersonInfo("zhangSan" , 90 , '男' , "学习kotlin语言" ) { println("显示结果:$it " ) } showPersonInfo("liSi" , 67 , '男' , "学习Java语言" , ::showResultImpl) } fun showResultImpl (result: String ) { println("显示结果:$result " ) } inline fun showPersonInfo (name: String , age: Int , sex: Char , study: String , showResult: (String ) -> Unit ) { val str = "name:$name ,age:$age ,sex:$sex ,study:$study " showResult(str) }
Kotlin语言的可空性特点 不会出现空指针异常
1 2 3 4 5 6 7 8 9 10 fun main () { var name: String = "zhangSan" println(name) var name2: String? name2 = null println(name2) }
Kotlin语言的安全调用操作符 1 2 3 4 5 6 7 fun main () { var name:String?="zhangSan" name =null val r = name?.capitalize() println(r) }
在Kotlin语言中使用带let的安全调用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 fun main () { var name :String ?=null name = "zhangSan" var r = name?.let{ if (it.isBlank()){ "Default" }else { "[$it ]" } } println(r) }
Kotlin语言中的非空断言操作符特点 1 2 3 4 5 6 7 8 9 fun main () { var name:String?=null name = "zhangSan" val r = name!!.capitalize(); println(r) }
Kotlin语言中对比使用if判断null值情况 1 2 3 4 5 6 7 8 9 10 11 fun main () { var name: String? = null name = "zhangSan" if (name != null ) { val r = name.capitalize(); println(r) } else { println("name is null" ) } }
Kotlin语言空合并操作符 1 2 3 4 5 6 7 8 fun main () { var info: String? = "李小龙" println(info ?: "info is null" ) println(info?.let { "[$it ]" } ?: "info is null" ) }
Kotlin语言中异常处理和自定义异常特点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.lang.IllegalArgumentExceptionfun main () { try { var info: String? = null checkException(info) println(info!!.length) } catch (e: Exception) { println(e) } } fun checkException (info: String ?) { info ?: throw CustomException() } class CustomException : IllegalArgumentException ("你的代码出现了问题" )
Kotlin语言先决条件函数 1 2 3 4 5 6 7 fun main () { val value1:String ?= null var value2:Boolean = false }
substring 1 2 3 4 5 6 const val INFO = "Good good study,day day up!" fun main () { val indexOf = INFO.indexOf(',' ) println(INFO.substring(0 , indexOf)) println(INFO.substring(0 until indexOf)) }
split 1 2 3 4 5 6 7 8 9 10 fun main () { val jsonText = "zhangSan,liSi,wangWu" val list = jsonText.split("," ) println("分割后list集合里面的元素有$list " ) val (v1, v2, v3) = list println("解构3个只读变量的值为:v1:$v1 ,v2:$v2 ,v3:$v3 " ) }
Kotlin语言的replace完成加密解密操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 fun main () { val sourcePwd = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" println("原始密码:$sourcePwd " ) val newPwd = sourcePwd.replace(Regex("[AKMNO]" )){ when (it.value){ "A" ->"9" "K" ->"3" "M" ->"5" "N" ->"1" "O" ->"4" else ->it.value } } println("加密后:$newPwd " ) val sourcePwdNew = newPwd.replace(Regex("[93514]" )){ when (it.value){ "9" ->"A" "3" ->"K" "5" ->"M" "1" ->"N" "4" ->"O" else ->it.value } } println("解密后:$sourcePwdNew " ) }
==与===比较操作 1 2 3 4 5 6 7 8 9 10 11 12 13 fun main () { val name1 = "Jack" val name2 = "Jack" val name3 = "jack" .capitalize() println(name1.equals(name2)) println(name1 == name2) println(name1 === name2) println(name1 == name3) println(name1 === name3) }
Kotlin语言的字符串遍历操作 1 2 3 4 5 6 7 8 9 10 11 fun main () { val str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" str.forEach { print("$it " ) } println() str.forEach { c -> print("$c " ) } }
Kotlin语言中数字类型的安全转换函数 1 2 3 4 5 6 7 8 9 10 11 fun main () { val number: Int = "666" .toInt() println(number) val number2: Int ? = "666.6" .toIntOrNull() println(number2) val number3: Int ? = "666" .toIntOrNull() println(number3) val number4: Int ? = "666.6" .toIntOrNull() println(number4 ?: "无法转换,输出为null" ) }
Kotlin语言中Double转Int与类型格式化 1 2 3 4 5 6 7 8 9 10 11 12 13 import kotlin.math.roundToIntfun main () { println(65.124543625 .toInt()) println(65.972674328 .toInt()) println(65.124654243 .roundToInt()) println(65.678937455 .roundToInt()) val r = "%.3f" .format(65.678937455 ) println(r) }
Kotlin语言的apply内置函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import java.io.Filefun main () { val info = "Welcome To My Class" println("info字符串的长度为:${info.length} " ) println("info最后一个字符为:${info[info.length-1 ]} " ) println("info全部转化小写为:${info.toLowerCase()} " ) println() val infoNew = info.apply { println("apply匿名函数内:${this} " ) println("info字符串的长度为:${length} " ) println("info最后一个字符为:${info[length-1 ]} " ) println("info全部转化小写为:${toLowerCase()} " ) } println("apply返回值:${infoNew} " ) info.apply { println("info字符串的长度为:${length} " ) }.apply { println("info最后一个字符为:${info[length-1 ]} " ) }.apply { println("info全部转化小写为:${toLowerCase()} " ) } println() val file = File("E:\\test.txt" ) file.setExecutable(true ) file.setReadable(true ) println(file.readLines()) println() file.apply { setExecutable(true ) }.apply { setReadable(true ) }.apply { println(readLines()) } }
apply: .apply 1.apply函数返回类型由调用对象本身决定 2.apply函数的匿名函数里面持有的是this == 调用对象本身
Kotlin语言的let内置函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 fun main () { val list = listOf(6 , 5 , 2 , 3 , 5 , 7 ) val value1 = list.first() val result1 = value1 + value1 println(result1) val result2 = listOf(6 , 5 , 2 , 3 , 5 , 7 ).let { it.first() + it.first() } println(result2) println(getMethod1(null )) println(getMethod2("zhangSan" )) println(getMethod3(null )) println(getMethod4("zhangSan" )) } fun getMethod1 (value: String ?) : String { return if (value == null ) "你传递的内容为null" else "欢迎${value} 登录" } fun getMethod2 (value: String ?) = if (value == null ) "你传递的内容为null" else "欢迎${value} 登录" fun getMethod3 (value: String ?) : String { return value?.let { "欢迎${value} 登录" } ?: "你传递的内容为null" } fun getMethod4 (value: String ?) = value?.let { "欢迎${value} 登录" } ?: "你传递的内容为null"
let: .let 1.let函数返回类型是根据匿名函数最后一行变化而变化 2.let函数的匿名函数里面持有的是it == 调用对象本身
Kotlin语言的run内置函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 fun main () { val str = "My name is zhangSan" val r1: Float = str.run { 5435.5f } println(r1) str.run { } str .run(::isLong) .run(::showText) .run(::mapText) .run(::println) str .let(::isLong) .let(::showText) .let(::mapText) .let(::println) str.run { length > 5 }.run { if (this ) "字符串长度大于5" else "字符串长度不大于5" }.run { "[$this ]" }.run { println(this ) } } fun isLong (str: String ) = str.length > 5 fun showText (isLong: Boolean ) = if (isLong) "字符串长度大于5" else "字符串长度不大于5" fun mapText (getShow: String ) = "[$getShow ]"
run: .run 1.run函数返回类型是根据匿名函数最后一行变化而变化 2.run函数的匿名函数里面持有的是this == 调用对象本身
Kotlin语言的with内置函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 fun main () { var str = "zhangSan" val len = with(str, ::getStrLen) val info = with(len, ::getLenInfo) val map = with(info, ::getInfoMap) with(map, ::showM) println() with(with(with(with(str) { length }) { "字符串长度为:$this " }) { "[$this ]" }) { println(this ) } } fun getStrLen (str: String ) = str.lengthfun getLenInfo (len: Int ) = "字符串长度为:$len " fun getInfoMap (info: String ) = "[$info ]" fun showM (content: String ) = println(content)
with: with() 1.with函数返回类型是根据匿名函数最后一行变化而变化 2.with函数的匿名函数里面持有的是this == 调用对象本身
Kotlin语言的also内置函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import java.io.Filefun main () { val str="ABCDEFGHIJKLMNOPQRSTUVWXYZ" str.also { println("str:$it " ) }.also { println("str装化为小写:${it.toLowerCase()} " ) }.also { println("长度为:${it.length} " ) } val file = File("E:\\test.txt" ) file.also { it.setExecutable(true ) }.also { it.setReadable(true ) }.also { println(it.readLines()) } }
also: .also 1.also函数返回类型由调用对象本身决定 2.also函数的匿名函数里面持有的是it == 调用对象本身
Kotlin语言的takeIf内置函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 fun main () { println(checkPermission("zhangSan" , "12345" )) println(checkPermission2("zhangSanSan" , "12345" )) } public fun checkPermission (name: String , pwd: String ) : String? { return name.takeIf { permissionSystem(name, pwd) } } public fun checkPermission2 (name: String , pwd: String ) : String { return name.takeIf { permissionSystem(name, pwd) } ?: "error" } fun permissionSystem (name: String , pwd: String ) : Boolean { return name == "zhangSan" && pwd == "12345" }
name.takeIf{ true/false }
true: 返回name false: 返回null 大多情况下都是 takeIf + 空合并操作符
一起使用
Kotlin语言的takeUnless内置函数 与takeIf功能是相反的
name.takeUnless{ true/false }
true: 返回null false: 返回name 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Manager { private var infoValue: String? = null fun getInfoValue () = infoValue fun setInfoValue (infoValue: String ) { this .infoValue = infoValue } } fun main () { val manager = Manager() manager.setInfoValue("zhangSan" ) val r = manager.getInfoValue().takeUnless { it.isNullOrBlank() } ?: "未经过任何初始化" println(r) }
List创建与元素获取 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 fun main () { val list = listOf("zhangSan" , "liSi" , "wangWu" , "zhaoLiu" ) println(list[0 ]) println(list[1 ]) println(list[2 ]) println(list[3 ]) println(list.getOrElse(3 ) { "越界" }) println(list.getOrElse(5 ) { "越界" }) println() println(list.getOrNull(3 )) println(list.getOrNull(5 )) println(list.getOrNull(5 ) ?: "越界" ) }
可变List集合 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 fun main () { val list = mutableListOf("zhangSan" , "liSi" , "wangWu" ) list.add("zhaoLiu" ) list.remove("wangWu" ) println(list) val list1:List<String> = list.toList() println(list1) val list2 = listOf(123 , 456 , 789 ) val list3: MutableList<Int > = list2.toMutableList() list3.add(890 ) list3.remove(123 ) println(list3) }
Kotlin语言的mutator函数 1 2 3 4 5 6 7 8 9 10 11 fun main () { val list: MutableList<String> = mutableListOf("zhangSan" , "liSi" , "wangWu" ) list += "张三" list += "李四" list -= "zhangSan" println(list) list.removeIf { it.contains("li" ) } println(list) }
List集合编历 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 fun main () { val list = listOf(1 , 2 , 3 , 4 , 5 , 6 , 7 ) for (i in list) { print("元素:$i " ) } println() list.forEach { print("元素:$it " ) } println() list.forEachIndexed { index, item -> print("下标:$index ,元素:$item " ) } }
Kotlin语言的解构语法过滤元素 1 2 3 4 5 6 7 8 9 10 11 12 fun main () { val list: List<String> = listOf("zhangSan" , "liSi" , "wangWu" ) val (value1, value2, value3) = list print(value1) print(value2) print(value3) println() val (_, n1, n2) = list println(n1) println(n2) }
Set创建与元素获取 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 fun main () { val set : Set<String> = setOf("zhangSan" , "liSi" , "zhaoLiu" , "zhangSan" ) println(set ) println(set .elementAt(0 )) println(set .elementAt(1 )) println(set .elementAt(2 )) println() println(set .elementAtOrElse(0 ) { "越界" }) println(set .elementAtOrElse(3 ) { "越界" }) println() println(set .elementAtOrNull(0 )) println(set .elementAtOrNull(3 )) println() println(set .elementAtOrNull(3 ) ?: "越界" ) }
可变Set集合 1 2 3 4 5 6 7 8 fun main () { val set : MutableSet<String> = mutableSetOf("zhangSan" , "liSi" , "zhaoLiu" ) set += "张三" set -= "zhangSan" set .add("李四" ) set .remove("liSi" ) println(set ) }
Kotlin语言的集合转换与快捷函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 fun main () { val list :MutableList<String> = mutableListOf("zhangSan" ,"liSi" ,"Jack" ,"Tom" ,"zhangSan" ) println(list) val set =list.toSet() println(set ) val list2 = list.toSet().toList() println(list2) println(list.distinct()) println(list.toMutableSet().toList()) }
Kotlin中的数组类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import java.io.Filefun main () { val intArray = intArrayOf(1 , 2 , 3 , 4 , 5 ) println(intArray[0 ]) println(intArray[1 ]) println(intArray[2 ]) println(intArray[3 ]) println(intArray[4 ]) println() println(intArray.elementAtOrElse(0 ) { -1 }) println(intArray.elementAtOrElse(5 ) { -1 }) println() println(intArray.elementAtOrNull(0 )) println(intArray.elementAtOrNull(5 )) println(intArray.elementAtOrNull(5 ) ?: "越界" ) println() val charArray = listOf('A' , 'B' , 'C' , 'D' ).toCharArray() println(charArray) val objArray = arrayOf(File("AAA" ), File("BBB" ), File("CCC" )) }
map创建 1 2 3 4 fun main () { val map1 = mapOf("zhangSan" to (687.90 ), "liSi" to 7868.90 ) val map2 = mapOf(Pair("zhangSan" , 5676.78 ), Pair("liSi" , 6768.66 )) }
读取map值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 fun main () { val map1 = mapOf("zhangSan" to 123 , "liSi" to 566 ) println(map1["zhangSan" ]) println(map1["xxx" ]) println(map1.getOrDefault("zhangSan" , -1 )) println(map1.getOrDefault("xxx" , -1 )) println(map1.getOrElse("zhangSan" ) { -1 }) println(map1.getOrElse("xxx" ) { -1 }) println(map1.get ("zhangSan" )) println(map1.get ("xxx" )) println(map1.getValue("zhangSan" )) }
遍历map 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 fun main () { val map1 = mapOf("zhangSan" to 123 , "liSi" to 566 , Pair("Jack" , 678 )) map1.forEach { println("k:${it.key} , v:${it.value} " ) } println() map1.forEach { key, value -> println("k:$key , v:$value " ) } println() map1.forEach { (k, v) -> println("k:$k , v:$v " ) } println() for (item in map1) { println("k:${item.key} , v:${item.value} " ) } }
可变Map集合 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 fun main () { val map = mutableMapOf("zhangSan" to 123 , "liSi" to 566 , Pair("Jack" , 678 )) map += "AAA" to (123 ) map += "BBB" to 123 map -= "zhangSan" map["CCC" ] = 345 map.put("DDD" , 678 ) val r1 = map.getOrPut("FFF" ){4654 } val r2 = map.getOrPut("AAA" ){4654 } println(r1) println(r2) println(map) }
Kotlin语言的定义类与field关键字 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Person { var name = "Tom" var value = "ABCD" var info = "Tom and Jerry" get () = field.capitalize() set (value) { field = "**[$value ]**" } } fun main () { Person().name = "Jerry" println(Person().name) println(Person().info) Person().info = "liSi" println(Person().info) }
Kotlin语言的计算属性和防范竞态条件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Person { val number = 0 val number2: Int get () = (1. .1000 ).shuffled().first() var info: String? = "" fun getShowInfo () : String { return info?.let { if (it.isBlank()) { "空值" } else { "info:$it " } } ?: "null" } } fun main () { println(Person().number) println(Person().number2) println(Person().getShowInfo()) }
Kotlin语言的主构造函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Person (_name: String, _sex: Char , _age: Int , _info: String) { var name = _name get () = field private set (value) { field = value } val sex = _sex val age = _age get () = if (field < 0 ) -1 else field val info = _info get () = "[$field ]" fun show () { println(name) println(sex) println(age) println(info) } } fun main () { val p = Person(_name = "zhangSan" , _sex = '男' , _age = 78 , _info = "study" ) p.show() }
Kotlin语言的主构造函数里定义属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Person (var name: String, val sex: Char , val age: Int , val info: String) { fun show () { println(name) println(sex) println(age) println(info) } } fun main () { val p = Person(name = "zhangSan" , sex = '男' , age = 78 , info = "study" ) p.show() }
Kotlin次构造函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Example (name:String){ constructor (name:String,sex:Char ):this (name){ println("name:$name ,sex:$sex " ) } constructor (name:String,sex:Char ,info:String):this (name){ println("name:$name ,sex:$sex ,info:$info " ) } } fun main () { val p = Example("zhangSan" ) Example("liSi" ,'男' ) Example("Rose" ,'女' ,"like Jack" ) }
Kotlin语言的构造函数中的默认参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Example (name:String="zhangSan" ){ constructor (name:String="zhangLi" ,sex:Char ='男' ):this (name){ println("name:$name ,sex:$sex " ) } constructor (name:String="zhangSui" ,sex:Char ,info:String="like marry" ):this (name){ println("name:$name ,sex:$sex ,info:$info " ) } } fun main () { Example() }
Kotlin语言的初始化块 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Test (username:String,userage:Int ,usersex:Char ){ init { println("主构造函数 $username $userage $usersex " ) require(username.isNotBlank()){ "username is null" } require(userage>0 ){"userage does not true" } require(usersex=='男' ||usersex=='女' ){"sex error" } } constructor (username: String):this (username,87 ,'男' ){ println("次构造函数 $username " ) } } fun main () { Test("zhangSan" , userage = 88 , usersex = '男' ) println() Test("liSi" ) println() }
Kotlin语言的构造初始化顺序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class A (_name: String, val sex: Char ){ val mName = _name init { val nameValue = _name println("init代码块 name:$nameValue " ) } constructor (name: String, sex: Char , age: Int ) : this (name, sex) { println("次构造 name:$name ,sex:$sex ,age:$age " ) } } fun main () { A("zhangSan" , '男' , 89 ) }
Kotlin语言的延迟初始化lateinit 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class A { lateinit var responseInfo:String fun load () { responseInfo = "加载成功" } fun showResponseResult () { if (::responseInfo.isInitialized){ println("responseInfo:$responseInfo " ) }else { println("没有初始化加载" ) } } } fun main () { val r = A() r.showResponseResult() }
Kotlin语言的惰性初始化by lazy 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class KtBase { val databaseData2 by lazy { readSQLServerDatabaseAction() } private fun readSQLServerDatabaseAction () : String { println("loading..." ) println("loading..." ) println("loading..." ) println("loading..." ) println("loading..." ) return "database load success." } } fun main () { val p = KtBase() Thread.sleep(5000 ) println("结果:${p.databaseData2} " ) }
Kotlin进阶 双冒号::引用 ::后面只能引用 属性 、函数 和类 ,变量是无法被引用的,引用出来的是对应的引用对象,我们可以把引用当成反射来进行编写,能清晰一点,基础已经讲解了,这里就不在赘述。
by关键字各种委托 类的委托 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 fun main () { println(HomeService(HomeDaoImpl()).getAllData()) } interface HomeDao { fun getAllData () : List<String> } class HomeDaoImpl : HomeDao { override fun getAllData () : List<String> = listOf("home" ) } class HomeService (homeDaoImpl: HomeDaoImpl) : HomeDao by homeDaoImpl { fun getRedisData () : String { return "redis" } }
使用by关键字进行委托:
可以降低直接实现HomeDao而导致的冗余 不需要使用类似SpringBoot的注入字段 也可以有多个委托
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 fun main () { println(HomeService(HomeDaoImpl(),ADaoImpl()).getAllData()) println(HomeService(HomeDaoImpl(),ADaoImpl()).getById(123 )) } interface HomeDao { fun getAllData () : List<String> } interface ADao { fun getById (id: Int ) : String } class HomeDaoImpl : HomeDao { override fun getAllData () : List<String> = listOf("home" ) } class ADaoImpl : ADao { override fun getById (id: Int ) : String { return id.toString() } } class HomeService (homeDaoImpl: HomeDaoImpl, aDaoImpl: ADaoImpl) : HomeDao by homeDaoImpl, ADao by aDaoImpl { fun getRedisData () : String { return "redis" } }
属性委托 属性在顶层函数中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import kotlin.properties.ReadWritePropertyimport kotlin.reflect.KPropertyfun main () { var test: String by TestClass() test = "123" println(test) } class TestClass : ReadWriteProperty <Nothing?, String > { private var myVar = "" override fun getValue (thisRef: Nothing ?, property: KProperty <*>) : String = myVar override fun setValue (thisRef: Nothing ?, property: KProperty <*>, value: String ) { myVar = value } }
属性在类中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import kotlin.properties.ReadWritePropertyimport kotlin.reflect.KPropertyfun main () { A().apply { aTest = "hello" println(aTest) } } class A { var aTest: String by TestClass() } class TestClass : ReadWriteProperty <A, String > { private var myVar = "" override fun getValue (thisRef: A , property: KProperty <*>) : String = myVar override fun setValue (thisRef: A , property: KProperty <*>, value: String ) { myVar = value } }
延迟委托by lazy 查看基础部分
observable监听委托 可以用来监听值的改变,类似于vue中的watch
1 2 3 4 5 6 fun main () { var test by Delegates.observable("hello" ) { _, oldVal, newVal -> println("oldVal:$oldVal newVal:$newVal " ) } test = "world" }
自己实现一个简易监听
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import kotlin.properties.ReadWritePropertyimport kotlin.reflect.KPropertyfun main () { var test by TestClass("hello" ) { oldVal, newVal -> println("oldVal:$oldVal newVal:$newVal " ) } test = "world" } class TestClass (private var defaultVal: String = "" , val onChange: (String, String) -> Unit ) : ReadWriteProperty<Nothing ?, String> { override fun getValue (thisRef: Nothing ?, property: KProperty <*>) : String = defaultVal override fun setValue (thisRef: Nothing ?, property: KProperty <*>, value: String ) { if (defaultVal == value) return onChange(defaultVal, value) defaultVal = value } }
泛型 泛型实际上就是一个类型参数,在我们不确定传入类型时,就可以指定为泛型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 fun main () { A(1 ).test(2 ) 1. b(2 ) } class A <T:Number >(override val param: T) : B<T>(), C<T> { override fun test (data : T ) { println(data ) } } abstract class B <T > { abstract fun test (data : T ) } interface C <T > { val param: T } fun <T> a (data : T ) {} fun <T> T.b (data : T ) { println(data ) println(this ) }
泛型擦除:
Java 泛型的类型擦除是指在编译时将所有泛型类型参数擦除,转换为 Object 类型,然后在运行时无法获得泛型类型的信息。类型擦除的主要目的是避免过多的创建类而造成的运行时的过度消耗。
kotlin中也存在,但kotlin可以将函数声明为 inline 函数,并使用 reified 关键字保存一下。但声明为 inline 函数将增加编译后的代码量。
1 2 3 4 5 6 7 8 9 10 fun main () { A(1 ).test(2 ) } class A <T >(param:T){ inline fun <reified T> test (data :T ) { val java = T::class .java println(java.simpleName) } }
out和in关键字
在泛型前面加out 关键字,泛型就具有了协变 的特性,你可以从一个子类转换为一个父类,不能用于函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 fun main () { val dog: AnimalManager<Dog> = object : AnimalManager<Dog> { override fun getAnimal () : Dog { return Dog() } } handlerAnimal(dog) } abstract class Animal class Dog : Animal () { val name = "dog" } interface AnimalManager <out T > { fun getAnimal () : T } fun handlerAnimal (animalManager: AnimalManager <Animal >) { val dog: Dog = animalManager.getAnimal() as Dog println(dog.name) }
在泛型前面加in 关键字,泛型就具有了逆变 的特性
1 2 3 4 5 6 7 8 9 interface Read <out T > { fun getItem () :T } interface Write <in T > { fun setItem (data : T ) }
*通配符
*==Any?
1 2 3 4 5 6 fun main () { val list: List<*> = listOf("1213" , 123 , null ) list.forEach { println(it is Int ) } }
where
给泛型添加约束
1 2 3 4 5 6 7 8 9 10 11 12 13 14 fun main () { MyClass<TestClass>() test<TestClass>() } interface A interface B interface C class TestClass : A , B , C class MyClass <T > where T : A , T : B , T : C fun <T> test () where T : A, T : B, T : C {}
Kotlin 特性 kotlin1.5 无限持续时间值Duration 表示一个时刻与另一个瞬间相距的时间量。当第二个瞬间早于第一个瞬间时,可能会出现负持续时间。该类型可以存储持续时间值,精度可达 ±146 年,精度可达纳秒,毫秒精度可达 ±1.46 亿年。如果在 kotlin 中提供了持续时间返回操作。time 产生的持续时间值不适合上述范围,返回的 Duration 是无限的。
INFINITE 可用于表示无限超时。若要构造持续时间,请使用扩展函数 toDuration 或扩展属性 hours、minutes、seconds 等,这些属性可用于 Int、Long 和 Double 数值类型。若要获取以特定持续时间单位表示的此持续时间的值,请使用函数 toInt、toLong 和 toDouble 或属性 inWholeHours、inWholeMinutes、inWholeSeconds、inWholeNanoseconds 等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 inline fun timeCost (block: () -> Unit ) : Long { val startTime = System.currentTimeMillis() block() return System.currentTimeMillis() - startTime } inline fun <T> timeCostValue (block: () -> T ) : Pair<T, Long > { val startTime = System.currentTimeMillis() val result = block() return result to System.currentTimeMillis() - startTime } suspend fun main () { val duration = measureTime { Thread.sleep(100 ) } println("measureTime ===> duration: $duration " ) val timeCost = timeCost { Thread.sleep(100 ) } println("timeCost ===> timeCost: $timeCost " ) val (value, measuredTime) = measureTimedValue { Thread.sleep(100 ) 100 } println("measureTimedValue ===> value: $value , measuredTime: $measuredTime " ) val (value2, measuredTime2) = timeCostValue { Thread.sleep(100 ) 100 } println("timeCostValue ===> value: $value2 , measuredTime: $measuredTime2 " ) val scope = CoroutineScope(Dispatchers.IO) scope.launch { val time = measureTime { delay(1000 ) } println(time) val mark = TimeSource.Monotonic.markNow() delay(1000 ) println(mark.elapsedNow()) }.join() }
JvmRecord注解 为了迎合java的record类,同时@JvmRecord class属性只能是val,不能是var,因为java中的record数据是不可变的,同时record中只能定义静态变量
1 2 3 4 5 6 7 8 9 10 11 12 @JvmRecord data class KotlinPerson (val name: String, val age: Int )data class PersonNotRecord (val name: String, val age: Int ) fun main () { val javaPerson = JavaRecordUse.JavaPerson("yuanyuan" , 18 ) val kotlinPerson = KotlinPerson("yuanyuan" , 18 ) println(javaPerson) println(kotlinPerson) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class JavaRecordUse { public record JavaPerson (String name, int age) { public JavaPerson { if (name == null ) throw new IllegalArgumentException ("name cannot be null" ); if (age < 0 || age > 100 ) throw new IllegalArgumentException ("age must between 0 and 100" ); } } public static void main (String[] args) { var javaPerson = new JavaPerson ("yuanyuan" , 18 ); System.out.println("javaPerson.name = " + javaPerson.name() + ", javaPerson.age = " + javaPerson.age()); var kotlinPerson = new KotlinPerson ("yuanyuan" , 18 ); System.out.println("kotlinPerson.name = " + kotlinPerson.name() + ", kotlinPerson.age = " + kotlinPerson.age()); var personNotRecord = new PersonNotRecord ("yuanyuan" , 18 ); System.out.println("personNotRecord.name = " + personNotRecord.getName() + ", personNotRecord.age = " + personNotRecord.getAge()); } }
value class 用来定义基本类型那样的数值,取代inline class,只能定义一个参数
1 2 3 4 inline class DurationForLegacy (val value: Long )@JvmInline value class DurationForNew (val value: Long )
kotlin1.6 Exhaustive when 使用 when 时不要漏掉任何分支,1.6只是警告,1.7直接报错
suspend父类、挂起转换 使用suspend作为父类时注意:
不能在超类型列表中混合使用普通函数类型和挂起函数类型。 不能使用多个挂起功能超类型。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class MyClickAction0 : () -> Unit { override fun invoke () { TODO() } } class MyClickAction1 : suspend () -> Unit { override suspend fun invoke () { TODO() } } fun launchOnClick (action: suspend () -> Unit ) {}fun getSuspending (suspending: suspend () -> Unit ) {}fun suspending () {}fun test (regular: () -> Unit ) { getSuspending { } getSuspending(::suspending) getSuspending(regular) val x: () -> Unit = {} val y: suspend () -> Unit = {} } fun main () { launchOnClick(MyClickAction0()) launchOnClick(MyClickAction1()) val clickAction1: suspend () -> Unit = MyClickAction1() }
注解实例化与Repeatable 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 annotation class X @Target(AnnotationTarget.TYPE_PARAMETER) annotation class BoxContent class Box <@BoxContent T > {}@Repeatable annotation class Tag (val value: String)annotation class TagContainer (val value: Array<JvmTag>)@JvmRepeatable(TagContainer::class) annotation class JvmTag (val value: String)@Tag("hello" ) @Tag("world" ) class Abc fun main () { val x = X() }
递归泛型推导增强 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 abstract class AbsBuilder <B : AbsBuilder<B >> { val self: B = this as B private var id: Int ? = null fun setId (id: Int ) : B { this .id = id return self } } open class MyBuilder1 : AbsBuilder <MyBuilder1 >() { private var name: String? = null fun setName (name: String ) : MyBuilder1 { this .name = name return this } } class MyBuilder2 : MyBuilder1 () { private var age: Int ? = null fun setAge (age: Int ) : MyBuilder2 { this .age = age return this } } fun main () { MyBuilder1().setId(1 ).setName("yuanyuan" ) (MyBuilder2().setId(2 ).setName("yuanyuan" ) as MyBuilder2).setAge(22 ) }
此时需要修改MyBuilder1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 abstract class AbsBuilder <B : AbsBuilder<B >> { val self: B = this as B private var id: Int ? = null fun setId (id: Int ) : B { this .id = id return self } } open class MyBuilder1 <B : MyBuilder1<B >> : AbsBuilder <B >() { private var name: String? = null fun setName (name: String ) : B { this .name = name return self } } class MyBuilder2 : MyBuilder1 <MyBuilder2 >() { private var age: Int ? = null fun setAge (age: Int ) : MyBuilder2 { this .age = age return this } } fun main () { MyBuilder1().setId(1 ).setName("yuanyuan" ) MyBuilder2().setId(2 ).setName("yuanyuan" ).setAge(22 ) }
Builder Inference 延迟的类型推导
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 import kotlin.experimental.ExperimentalTypeInferenceclass Container <T > { fun getValue () : T = TODO() fun setValue (value: T ) { } } @OptIn(ExperimentalTypeInference::class) fun <T> buildContainer (@BuilderInference builder: Container <T >.() -> Unit ) {} fun main () { buildContainer { setValue(10 ) getValue() } buildList { add("hello" ) add("world" ) set (1 , "kotlin" ) get (0 ) } buildMap { put("hello" , 1 ) } buildSet { add(100 ) } sequence { yield(100 ) } }
Context Receiver 开启Context Receiver
build.gradle.kts
1 2 3 4 val compileKotlin: KotlinCompile by taskscompileKotlin.kotlinOptions { freeCompilerArgs = listOf("-Xcontext-receivers" ) }
在logger中的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 import com.google.gson.Gsonimport kotlinx.coroutines.flow.asFlowinterface Logger { fun log (message: Any ?) } object StdOutLogger : Logger { override fun log (message: Any ?) = println(message) } object StdErrLogger : Logger { override fun log (message: Any ?) = System.err.println(message) } object JsonLogger : Logger { override fun log (message: Any ?) = println(Gson().toJson(message)) } fun <E> List<E> .loggerOnEach (logger: Logger ) : List<E> { forEach { logger.log(it) } return this } context(Logger) fun <E> List<E> .loggerOnEach () : List<E> { forEach { log(it) } return this } data class User (val id: Int , val name: String)fun main () { listOf(1 , 2 , 3 ).loggerOnEach(StdOutLogger).asFlow() listOf("1" , "2" , "3" ).loggerOnEach(StdOutLogger) "Hello" .toList().loggerOnEach(StdOutLogger) with(StdErrLogger) { listOf(1 , 2 , 3 ).loggerOnEach() listOf("1" , "2" , "3" ).loggerOnEach() "Hello" .toList().loggerOnEach() } with(JsonLogger) { listOf(User(1 , "yuanyuan" ), User(2 , "kotlin" )).loggerOnEach() } }
dispatch receiver:如果一个类有一个函数,那这个类就是这个函数的 dispatch receiver
extension receiver:定义扩展函数时,对于扩展函数来讲,扩展的类型就是他的 extension receiver