咱们好,本次的文章主要是聊聊Kotlin1.5和1.6版别供给的一些特性,希望能扩充咱们的视野,假如能对你日常的开发带来协助,这将是我写这篇文章最大的价值。

一. 挂起函数类型能够作为父类型

在了解这个之前,先看下函数类型做父类型的用法吧:

class Block : () -> String {
    override fun invoke(): String {
        return ""
    }
}
fun test(list: MutableList<() -> String>) {
    list.add(Block())
}

Block类的父类型便是() -> String,而且需要重写办法invoke()办法。当需要调用该类时,能够经过Block().invoke()或者 Block()()完成。

咱们将上面的反编译成java看下完成原理:

聊聊kotlin1.5和1.6版本提供的一些新特性

其实本质上便是完成了Function0这个接口,就那么朴实无华:

聊聊kotlin1.5和1.6版本提供的一些新特性

假如说咱们充任父类型的函数类型为带一个参数的(Int) -> String,那么将会是完成Function1这个接口;以此类推,函数类型每新增一个参数,完成的接口FunctionX中X就要加一,当时这个不能无限新增,现在看到的FunctionX类型的接口最高为Function22

咱们能够看下LeakCanary的源码FragmentAndViewModelWatcher,就有用到这个特性:

聊聊kotlin1.5和1.6版本提供的一些新特性
聊聊kotlin1.5和1.6版本提供的一些新特性

以上都是一般函数类型作为父类型的解说,接下来就看下挂起函数类型作为父类型吧,无非便是一般在函数类型前面添加了一个suspend要害字。

class Block : suspend () -> String {
    override suspend fun invoke(): String {
        return withContext(Dispatchers.IO) {
            //模拟耗时
            delay(2000)
            "result"
        }
    }
}

这样咱们就能够愉快的invoke办法中调用协程官方api履行一些比方耗时操作了,十分的好用。

发编译下代码,其实能够看到本质上还是完成了Function1接口,为什么挂起来的函数类型明明没有参数,为啥不是完成Function0接口呢?咱们看下反编译的代码:

聊聊kotlin1.5和1.6版本提供的一些新特性

invoke办法会默认新增一个Continuation类型的参数,这个是协助咱们履行挂起函数类型的要害,所以最终完成的接口为Function1

至于挂起的原理,比方上图invoke办法中详细的代码逻辑太杂乱了,想要了解协程挂起原理的给咱们推荐一篇文章阅览:写给Android工程师的协程指南。

想要运用这个特性,要么你的kotlin插件版别升级到了1.6.0及以上,要么你的插件版别为1.5.30而且在build.gradle脚本中添加装备:

聊聊kotlin1.5和1.6版本提供的一些新特性

二. 安稳的挂起类型转化

在kotlin1.6.0的版别,完成了安稳的一般函数类型到挂起函数类型的隐式转化,说了这么多,接下来咱们经过一个比方进行了解:

fun execute(block: suspend () -> Unit) {
}
fun test(block: () -> Unit) {
    execute(block)
}

首要咱们声明晰一个execute()办法,其间办法的参数为挂起函数类型;然后test()办法参数声明晰一个一般函数类型;最后咱们在test()办法中成功调用了execute()办法并将一般函数类型的参数传递给了execute()办法。

上面这就完成了一次一般函数类型到挂起函数类型的转化,请留意,这个操作可不能反着来,也便是由挂起函数类型转化成一般函数类型是不可能的,毕竟一般函数类型可没有协程代码的履行环境

官方供给这个特性的目的在笔者看来主要是添加兼容性吧,而且咱们不要以为这样转化会添加挂起的开支,毕竟:

由于一般函数类型根本不存在所谓的挂起点,即便转化成挂起函数类型且被履行,也不会履行任何挂起操作的,仅仅作为一个一般的函数履行并回来罢了。

三. 注解类能够被实例化

咱们看下java中一个比方:

定义一个注解HuiHui

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface HuiHui {
     String content();
}

这个注解本质上便是一个接口,自然在java中是能够被完成的:

public class HuiImpl implements HuiHui {
    @Override
    public String content() {
        return null;
    }
    @Override
    public Class<? extends Annotation> annotationType() {
        return null;
    }
}

上面的场景在java中是能够的,那咱们看下kotlin中的注解可不能够这样搞:

聊聊kotlin1.5和1.6版本提供的一些新特性

报错了看到了不,提示注解类HuiPlus需要添加open,可是给其添加open就会提示:

聊聊kotlin1.5和1.6版本提供的一些新特性

除了上面这种写法,这样也会报错的:

聊聊kotlin1.5和1.6版本提供的一些新特性

总之一句话,kotlin中的注解不支撑实例化。Kotlin官方就留意到了这点,这样今后还能和java之间愉快的游玩嘛,所以在1.5.30插件版别出手了。

聊聊kotlin1.5和1.6版本提供的一些新特性

简略一句话,注解类支撑被实例化,接下来咱们经过代码进行实战。

聊聊kotlin1.5和1.6版本提供的一些新特性

能够看到上面的代码没有丝毫报错。其实咱们是能够经过kotlin的反射库是能够调用注解类的结构办法的,可是这样显得繁琐杂乱,直接供给一个实例化注解类的特新岂不是愈加美哉?

一般假如咱们想了解kotlin是怎么完成这种才能的,都会尝试反编译成java代码看下。但惋惜的是,对于kotlin注解实例化的细节被躲藏掉了,反编译成java也没有协助,躲藏掉的优点是答应编译器做一些隐式的优化工作

假如想要运用这个特性,和参阅上面第一节内容末尾的操作。

四. 支撑对类泛型声明注解

解说起来很麻烦,直接给咱们上代码:

@Target(AnnotationTarget.TYPE_PARAMETER)
annotation class FLAG
class Annotation2<@FLAG T> {
    val content: String = ""
}

能够看到我声明晰一个FLAG注解,而且经过@Target(AnnotationTarget.TYPE_PARAMETER)约束只能给泛型类型润饰。

这个特性相当于把咱们注解的范围愈加颗粒化了,答应咱们以在愈加细致的维度中去处理问题。而且,请留意,这个注解最终是会被编译到jvm字节码的,所以经过Android自定义注解处理器是能够拿到并处理该注解的。 这样就愈加扩展了该特性的运用范围。

假如想要运用这个特性,和参阅上面第一节内容末尾的操作。

五. 长时间支撑对kotlin插件旧版别的保护

聊聊kotlin1.5和1.6版本提供的一些新特性

从kotlin1.6.0开始,kotlin官方将长时间支撑保护对当时安稳版别的过去三个旧版别的保护,换句话说,假如当时安稳版别为1.6.0,那么对于kotlin1.3、kotlin1.4和kotlin1.5也是继续进行保护的。

六. 总结

本篇文章主要是对kotlin1.5和1.6版别新增的特性做了一些解说,小而美的那种。我这里并没有列举全所有新增的特性,那样对于咱们和我都是一个负担,仅仅拿出一些比较典型的特性共享给咱们。

请留意,假如由某个特性十分适合打开讲讲,以及对于咱们开发很有协助的话,比方@Jvm-default=all、@BuilderInference等等这些特性,我一般都是专门出一篇文章针对这些特性进行解说的,咱们感兴趣能够看下下面的历史文章列表。

七. 历史文章

@JvmDefaultWithCompatibility优化小技巧,了解一下~

优化@BuilderInference注解,Kotlin高版别下了这些“毒手”!

kotlin密封sealed class/interface的迭代之旅

八. 参阅列表

kotlinlang.org/docs/whatsn…

kotlinlang.org/docs/whatsn…

hub.nuaa.cf/Kotlin/KEEP…

youtrack.jetbrains.com/issue/KT-25…


本文正在参与「金石方案」

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。