zoukankan      html  css  js  c++  java
  • Kotlin

    Kotlin契约

    Contract是Kotlin1.3的东西,比较新,目前还是处于实现性阶段(Experimental),即API在稳定版之前可能会发生变动。由于是实现性API,使用时需要额外添加注解,下面代码中会具体讲到。

    配置环境

    在project的gradle文件中

    由于契约处于实验性

    可以通过添加以下编译器选项(可选),这样就不用在使用契约时处处添加注解了

    在Module的gradle文件中

    为何要使用契约

    先看一下下面这段简单的代码

    getValue中调用一次runFun,运行时效果相当于把ret = 15调用了一次,注意是运行时,在编译时编译器并不知道runFun调用时传入的action有无被调用,因而编译时报错Variable 'ret' must be initialized

    再看一个类似的例子

    当字符串不为null时则将长度打印出来。

    It works fine.

    但如果程序中对字符串有很多这种判断,应该就会想到这个判断写成一个函数,减少代码冗余。于是就可能写成下面的版本

    这个版本对可空字符串的检查封装成了拓展函数形式,一眼望上去,聪明的编译器应该会在s.length的地方,有一个smart cast,将String?自动转换成String以使得length能正确被调用,但事实却是:编译器报错
    Only safe (?.) or non-null asserted(!!.) calls are allowed on a nullable reciever of type String?,编译器并没有做上述类型转换,Why?

    不难解释,一般函数的调用都是在运行时知道结果的,上述的notNullrunFun自然也是如此,函数调用的结果无法作为调用处编译时的上下文,即函数内部在编译时在调用处是不可见的,因此编译器无法通过这个上下文作出smart cast的行为

    因此不要太难为编译器,我们应该给编译器一点提示,契约正式出场!

    使用契约

    runFun 的契约版本

    先来解释一下这段代码含义

    我们在runFun的开头加入了contract函数

    其接受带一个无参无返回值的函数,而且这个函数还有一个值接收者ContractBuilder用于提供callsInPlacereturns等函数的调用

    其中上面的callsInPlace两个参数,第一个是任意函数类型,第二个参数表示传入的函数会被调用的次数,比如例子中的InvocationKind.EXACTLY_ONCE表明函数在运行时会被执行一次。说到这里,大概可以猜到,contract面向编译器的,给编译器看的,就是为了向编译器表明调用contract函数的这个函数(比如上面的runFun)是做什么的,getValue中调用契约版的runFun函数,编译器就能知道,传入的action函数会被调用一次,即变量ret将会在运行时会被初始化成15。

    (除了InvocationKind.EXACTLY_ONCE外还有AT_LEAST_ONCE等常量,具体含义查阅文档)

    notNull 的契约版本

    contract 代码表明当implies后的值成立,函数将会返回returns函数中的内容,注意这里implies是一个中缀运算符

    所以notNull函数中的contract告诉了编译器,当字符串不为null时函数在运行时将会返回true

    契约能让编译器smart cast的能力进一步发挥出来,这也说明了你可以"欺骗"编译器,比如在刚才的notNull函数中,将returns中的true改成false(自己体会),而且再次说明契约在开发环境中为实验性API,这表明它即使能在kotlin标准库中的函数比如letcheckNotNull正常发挥作用,但是在你使用的时候,可能会有一些编译时的bug,而且将来API的使用可能会发生变动,所以请谨慎使用

    使用契约的好处

    其实契约的好处并不是体现在开发者如何去使用它,因为标准库已经提供了利用契约实现的各种函数,满足了开发者的日常需求

    分析契约 参考链接

    Effect.kt ,里面定义了几个直接和间接继承于Effect的接口,代码量不多,具体含义全部都写了出来

    各个主要接口之间的关系

    ContractBuilder.kt 中包含了使用契约时主要用到的函数,接口等

    契约使用需要注意的地方

    目前契约在使用时有以下限制

    1. 契约目前在kt标准库中大量被使用,但是不建议开发者使用,目前面向开发者的契约还有很多bug
    2. 我们只能在顶层函数体内使用契约,即我们不能在成员和类函数上使用它们。
    3. contract调用声明必须是函数体内第一条语句
    4. 编译器无条件地信任契约,这意味着程序员负责编写正确合理的契约,不要欺骗编译器它会伤心的

    总结

    契约的作用就是把函数行为(比如例子中的null-check,和对action的调用)告知给编译器,使得开发者可以把这些行为封装到函数中,同时还能发挥编译器的智能推导效果

  • 相关阅读:
    Nginx internal 指令限制访问图片资源文件
    Laravel 5 中文文档 CHM 版
    Educational Codeforces Round 89 (Rated for Div. 2)
    Markdown写的第一篇文章,猜猜里边有什么东西吧!
    Git暂存流程
    Java BIO、NIO与AIO的介绍(学习过程)
    如何在Mac中安装telnet
    使用IDEA编译java程序时,出现的编译错误: error:java:错误:不支持发行版本5
    Java中请优先使用try-with-resources而非try-finally
    Redis入门学习(学习过程记录)
  • 原文地址:https://www.cnblogs.com/nosae/p/14405749.html
Copyright © 2011-2022 走看看