1.3 发了,说两句关于 Kotlin SAM 的

Posted Kotlin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1.3 发了,说两句关于 Kotlin SAM 的相关的知识,希望对你有一定的参考价值。

1.3 RC 刚出来的时候,有人就不乐意了:说好的 Kotlin 的 SAM 呢?这个曾经存在于 1.3 的谣言当中的特性最终没有被加入到这个版本当中,群里有不少小伙伴表示:失望,哼。

何为 SAM

我们先来简单回顾下何为 SAM。它其实不是英文名 Sam,而是 Single Abstract Method,直接理解就是一个抽象的方法。Kotlin 很早就支持了对 参数包含只有一个方法的 Java 接口的 Java 方法的 SAM 转换,说起来有点儿拗口,我们看个例子:

 
   
   
 
  1. public interface Runnable {

  2.    public abstract void run();

  3. }

Runnable 是一个只有一个方法的 Java 接口,我们这时候还有这样的方法:

 
   
   
 
  1. void execute(Runnable command){

  2.    ...

  3. }

我们注意到 execute 方法有一个参数是 Runnable,那么在 Kotlin 当中使用 execute 时:

 
   
   
 
  1. execute {

  2.    ...

  3. }

Kotlin 允许给 execute 方法传入一个 Lambda 表达式,而不需要 Runnable 的实例,因为在 Kotlin 看来,这个方法它本身是可以接受两种类型的参数的: Runnable()->Unit

那么前面任何一个条件不符合,这个结果就不成立,例如如果 Runnable 是一个 Kotlin 类,或者 execute 是一个 Kotlin 方法,都不可以。

Kotlin 1.3 跳票的 Kotlin SAM 现在怎么样了

虽然 Kotlin 1.3 没有正式把对 Kotlin 的 SAM 丢出来,但确实他们已经在做这件事儿了:NewInference 和 SamConversionForKotlinFunctions ,也就是新的类型推断和对 Kotlin 函数的 SAM 转换 —— 后者依赖于前者。

我们直接看效果,同样对于前面的 Runnable,我们在 Kotlin 当中定义一个函数:

 
   
   
 
  1. fun foo(runnable: Runnable){

  2.    ...

  3. }

按照之前的写法,我们只能使用 Runnable 实例传参,现在呢?

 
   
   
 
  1. foo {

  2.    println("Hello")

  3. }

有了前面提到的两样,这个就合法了。当然如果你想要亲自体验一下,请在你的 gradle 当中配置:

 
   
   
 
  1. compileKotlin {

  2.    kotlinOptions {

  3.        freeCompilerArgs = ["-XXLanguage:+NewInference", "-XXLanguage:+SamConversionForKotlinFunctions"]

  4.    }

  5. }

hmmm,这个给人的感觉一点儿都不好,连 Experimental 都算不上的东西,小伙伴们怎么敢用呢?所以线上的代码大家可以保守一点。当然这也问题不大,毕竟大部分团队可能连 1.3 都来不及切换,何况这些隐藏特性呢。

不过大家也不要觉得这很遥远,因为 Gradle Kotlin DSL 的脚本本身就强开了这俩特性:

 
   
   
 
  1. @ScriptTemplateAdditionalCompilerArguments([

  2.    "-jvm-target", "1.8",

  3.    "-Xjsr305=strict",

  4.    "-XXLanguage:+NewInference",

  5.    "-XXLanguage:+SamConversionForKotlinFunctions"

  6. ])

  7. @SamWithReceiverAnnotations("org.gradle.api.HasImplicitReceiver")

  8. abstract class KotlinInitScript(

  9.    private val host: KotlinScriptHost<Gradle>

  10. ) : InitScriptApi(host.target) {

  11.    ...

  12. }

Kotlin 接口呢

尽管有些不太正规,但我们好歹体验了一把 Kotlin 函数的 SAM。问题是,这里定义的接口,仍然需要是 Java 接口,那么 Kotlin 接口呢?

答案是:还不行。

关于这个问题的讨论,可以参见 YouTrack 的讨论:SAM for Kotlin classes [https://youtrack.jetbrains.com/issue/KT-7770],大家可以看到这个问题的讨论从 Kotlin 1.0 之前就开始了,官方的顾虑主要是一旦引入了对 Kotlin 接口的 SAM,会对整个 Kotlin 的类型系统引入较大的复杂度。

那时候 Kotlin 还是一个相对早期的版本,很多很必要的功能、特性都没有实现(比如 kapt 直到 1.0.6 才相对完善),因此这样的一个 Feature 优先级自然也没有那么高了,更何况这个功能还会有对 Kotlin 的函数类型有潜在影响的风险呢。

后面的故事呢?

最近有本新书叫 Atomic Kotlin,由 Java 编程思想的作者 Bruce Eckel 和 JetBrains 团队的 Svetlana Isakova 合著。。额,怎么说呢,后者也是 Kotlin in Action (貌似还不错)的作者之一,不知道 Atomic Kotlin 是不是要继续砸 Bruce Eckel 招牌(呃,反正那本 Atomic Scala 简直了,感觉就像买了一本 A4 纸)。

好吧,这不是重点了,重点是这位 Svetlana Isakova 小姐姐在 KotlinConf 上面对 Kotlin 的新的(更强大的)类型推断系统做了介绍,也提到了对 Kotlin 函数的 SAM 支持,加上 Andrey 在 Closing Panel 上对 Type classes 的暧昧态度,下一个版本我们大胆猜测下可能是一个类型系统的增强版本,也许对 Kotlin 接口的 SAM 支持也会在 1.4 上获得 Experimental 资格。


以上是关于1.3 发了,说两句关于 Kotlin SAM 的的主要内容,如果未能解决你的问题,请参考以下文章

活久见系列:关于袁老的事情,还是说两句吧

给请求指点迷津的准新生说两句

给请求指点迷津的准新生说两句

Jenkins ,再认真的说两句

为鸿蒙OS说两句公道话(我对鸿蒙OS的一些看法)

为鸿蒙OS说两句公道话(我对鸿蒙OS的一些看法)