泛型
? extend T => out T 协变 传入只能是其子类 只能get
? super T => in T 逆变 传入只能是其父类 可以get/set
Object 相当于 Any?
String? 最高父类 Any?
fun main() {
var destNumber = arrayOf<Number>()
var srcDouble = arrayOf<Double>(1.2, 3.2, 24.2)
println(copyIn(destNumber,srcDouble))
copyOut(destNumber, srcDouble)
}
//逆变super
fun <T> copyIn(dest: Array<in T>, src: Array<T>) {//消费者
// PECS Producer extends Consumer Super
// 取 存
// ?extends ? super
// out 取出来 in 存进去
// 协变 逆变
src.forEachIndexed { index, value -> dest[index] = src[index] }
}
//协变
fun <T> copyOut(dest: Array<T>, src: Array<out T>) {//生产者
src.forEachIndexed { index, value -> dest[index] = src[index] }
}
高阶函数、lambda
将函数⽤作参数或返回值的函数
fun test(a:String ,display: (String)->Unit){//lambda 也是函数
display(a)
}
test("zero"){
}
//lambda
var temp: (Int,Int) -> Int
var sum = {x:Int,y:Int -> x +y}
com.zero.lib.kotlin.basic01.sum(1,2)
var tmp1:(Int) -> Unit
tmp1 ={ println("$it")
it+2
}//默认一个参数
扩展函数
T.xxx() {
}
常用高阶函数
//常用的高阶函数
run{
//执行一块独立代码块
}
val str = "kolit"
str.length
str.run {
length
}
with(str){
}
str.apply {
}
.apply {
}
.apply {
length
}
str.also {
it.length
}
str.let {
it.reversed()
}
val st1 = str.takeIf {
it.startsWith("sko")
}
lazy { }
协程
协程是轻量级的线程, 开销成本相比线程是十分廉价的。
创建协程
通常用launch 、aysnc、 runBlocking启动协程
// 启动一个全局协程
GlobalScope.launch { // 在后台启动⼀个新的协程并继续
delay(1000L)
println("World!")
}
runBlocking { // 但是这个表达式阻塞了主线程
delay(2000L) // ……我们延迟 2 秒来保证 JVM 的存活
}
在主协程用调用 job.join() ,会等待到子协程执行完。
coroutineScope作用域构建器用来设定协程作⽤域 ,它会创建⼀
个协程作⽤域并且在所有已启动⼦协程执⾏完毕之前不会结束。
suspend 修饰的函数为挂起函数,只能在协程内部使用。
取消协程
调用 job.cancel() 来取消。取消是协作的,调用了不一定取消,例如正在计算,可以在协程内部使用isActive表达式判断是不是已经取消。
有时取消了还要进行操作,可以用,但这是不阻塞的,有可能finally的未执行完就退了,此时可以用 withContext(NonCancellable) {……}
进行阻塞等待。
try{
}finally{
}
// 也可以设置超时
withTimeout(1300L) {
repeat(1000) { i ->
println("I'm sleeping $i ...")
delay(500L)
}
}
组合挂起函数
挂起函数在协程内部是顺序的,想要并发需使用aysnc块,返回结果需要用 .await()
获取
suspend fun doSomethingUsefulOne(): Int {
delay(1000L) // 假设我们在这⾥做了⼀些有⽤的事
return 13
}
suspend fun doSomethingUsefulTwo(): Int {
delay(1000L) // 假设我们在这⾥也做了⼀些有⽤的事
return 29
}
val time = measureTimeMillis {
val one = async { doSomethingUsefulOne() }
val two = async { doSomethingUsefulTwo() }
println("The answer is ${one.await() + two.await()}")
}
println("Completed in $time ms")
// 惰性启动
val time = measureTimeMillis {
val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
one.start() // 启动第⼀个
two.start() // 启动第⼆个
println("The answer is ${one.await() + two.await()}")
}
println("Completed in $time ms")
推荐使用方法
suspend fun concurrentSum(): Int = coroutineScope {
val one = async { doSomethingUsefulOne() }
val two = async { doSomethingUsefulTwo() }
one.await() + two.await()
}
val time = measureTimeMillis {
println("The answer is ${concurrentSum()}")
}
println("Completed in $time ms")
调度器
调度线程用那个线程跑
调度器 | 使用的线程 |
---|---|
runBlocking(默认) | 使用父层的上下文,main |
Dispatchers.Unconfined | main |
Dispatchers.Default | DefaultDispatcher-worker-1 |
newSingleThreadContext("MyOwnThread") | MyOwnThread |
when
when(code){
1 -> {xxx}
2 -> {xxx}
else -> {xxx}
}
伴生对象
相当于静态变量
companion object {
const val TAG = "Jin"
}
单例
private object Holder {
val INSTANCE = ApiClient()
}
companion object {
val instance by lazy { Holder.INSTANCE }
}
作用域函数
let
、run
、with
、apply
、also
区别
- 引用上下文对象的方式
- 返回值
上下文对象
this:run
、with
、apply
it:let
、also
// 当将上下文对象作为参数传递时,可以为上下文对象指定在作用域内的自定义名称。
返回值
apply
及also
返回上下文对象。let
、run
及with
返回 lambda 表达式结果.
主要区别表
函数 | 对象引用 | 返回值 | 是否是扩展函数 |
---|---|---|---|
let | it | Lambda 表达式结果 | 是 |
run | this | Lambda 表达式结果 | 是 |
run | - | Lambda 表达式结果 | 不是:调用无需上下文对象 |
with | this | Lambda 表达式结果 | 不是:把上下文对象当做参数 |
apply | this | 上下文对象 | 是 |
also | it | 上下文对象 | 是 |
以下是根据预期目的选择作用域函数的简短指南:
- 对一个非空(non-null)对象执行 lambda 表达式:
let
- 将表达式作为变量引入为局部作用域中:
let
- 对象配置:
apply
- 对象配置并且计算结果:
run
- 在需要表达式的地方运行语句:非扩展的
run
- 附加效果:
also
- 一个对象的一组函数调用:
with