美文网首页
预测一下Kotlin未来可能引入的新功能

预测一下Kotlin未来可能引入的新功能

作者: super可乐 | 来源:发表于2022-07-18 10:18 被阅读0次

    前言

    Kotlin 是一门开放的语言,不仅仅是源码的开放,任意使用者都可以直接参与它的建设。大家可以通过 YouTrack 向社区提出自己的 idea 和 issue ,其中一些呼声高的 issue 会进入 KEEP 交由 Kotlin 团队管理维护,并有可能被最终实现、出现在未来的某个版本中。

    本文将透过 YouTrack 中当前最热门的 issue 大胆预测一下 Kotlin 未来可能引入的新功能:

    • 命名空间
    • 多接受者扩展函数
    • 集合字面值
    • 双类型属性
    • 名字解构
    • 异常多重捕获
    • 包级访问

    如果你喜欢这些功能,可以去 YouTrack 为它们点赞投票。

    命名空间 (Namespace)

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

    Java 可以通过类名调用 Class 的静态方法或者静态变量,这无形中提供了一种 namespace 机制,方便快速索引某个常量或方法。 Kotlin 虽然鼓励开发者使用顶级方法替代 Util 类,但当这样的顶级方法太多时,我们也希望有类似的 namespace 机制出现。

    目前常见的 workaround 是使用 object 类替代静态方法,例如

    object DisplayUtil{
        fun dip2px(context:Context, px:Float) {
            ...
        }
    }
    
    

    Kotlin 标准库的 Delegates.notNull 、协程库的 Dispatchers.Default 等都是这样定义的,这种方式缺点是需要额外创建一个 object 对象,增加内存开销。

    也许未来你将看到一种 namespace 关键字,像下面这样使用

    namespace DiplayUtil {
        fun dip2px(context:Context, px:Float)
    }
    
    

    namespace 可以避免实例对象的创建,将在字节码阶段编译成 jvm 静态方法。

    多接受者扩展函数 (Multiple receivers)

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

    有时我们会在 Class 内定义扩展方法

    class View { 
       val Float.dp // Float is an extension receiver for dp property
           get() = this * resources.displayMetrics.density
          // this refers to Float
          // resources, or this@View.resources, is a property in View
    }
    
    

    这种扩展方法可以在 View 的内部使用,或者在外部借助 with 使用。

    with (view) {
       42f.dp
    }
    
    

    但实际情况是我们无法为像 View 这样的三方库中的类定义扩展方法,所以我们希望有一种能够定义多 receiver 的扩展方法的机制。

    未来有可能会引入 context 关键字,通过 context 可以定义两个甚至多个 receiver 的扩展方法

    context(View)
    val Float.dp
       get() = this * resources.displayMetrics.density
    
    

    上述代码等价于

    context(View)
    fun dp(view: View, float: Float) {
        float * view.resources.displayMetrics.density
    }
    
    

    顺便提一下,我更喜欢其中另一种建议的语法:

    fun (View, Float).dp() = this@Float * this@View.resources.displayMetrics.density
    
    

    虽然由于不符合 Kotlin 的语法习惯,已经被否掉了。。

    集合字面值(Collection literals)

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

    很多现代语言(Python,JS,Go 等等)都支持使用字面值定义集合,例如在 Python 中我们可以这样定义一个集合:

    new_array = ["a", "b", "c"]
    
    

    字面值的定义方式更加直观简洁,这在重数据操作的语言中显得非常重要。但 Kotlin 目前只能使用 listOfmapOfsetOfintArrayOf 等 builder 方法进行定义,需要开发者记忆多个方法名,而且 varags 也存在一些使用上的隐患。

    未来也许我们可以在 Kotlin 引入字面值定义:

    val list = [1, 2, 3] // has type of List<Int>
    val map = ["one": 1, "two": 2, "three": 3] // has type of Map<String, Int>
    
    

    以上字面值默认创建 Immutable 的 List 和 Map 类型集合,当然我们也可以在定义的同时明确指定集合类型:

    val set: Set<Int> = [1, 2, 3] // creates a Set<Int> 
    val map: MutableMap<String, Int> = ["one": 1, "two": 2, "three": 3] // creates a MutableMap
    
    

    数组可以使用下面方式创建,且可以实现类型推到,无需指定泛型

    val array = Array [1, 2, 3] // creates Array<Int>, note that "Int" was inferred here
    
    

    字面值的使用场景不止局限于集合,甚至可以在 data class 等一些“类集合”场景中使用

    data class Point(val x: Int, val y: Int)
    fun drawLine(from: Point, to: Point)
    
    // Normal Calling
    drawLine(Point(1, 2), Point(3, 4))
    // Calling with Collection literals
    drawLine([1, 2], [3, 4])
    
    
    

    双类型属性 (public&private property type)

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

    我们经常有这种需求:一个类的属性对内使用 Mutable 类型方便使用,而对外只想暴露 Immutable 类型,避免随意修改,提高安全性。

    此时,通常需要我们分别定义两个成员:

    
    //List
    private val _items = mutableListOf<Item>()
    val item : List<Item> = _items
    
    //LiveData
    private val _list = MutableLiveData<List<News>>()
    val list : LiveData<List<News>> get() = _items
    
    
    

    由于上述写法冗余,有人为了图方便可能直接对外暴露 Mutable 类型,容易造成隐患。

    未来 Kotlin 或许会引入下面的语法,属性在定义时对外只暴露其 Immutable 的抽象类型,保证安全性的同时,减少模板代码:

    private val items = mutableListOf<Item>()
            public get(): List<Item>
    
    

    名字解构(Name based destructuring)

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

    我们在访问 data class 或者 Pair、 Triple 等类型时,经常会使用解构语法

    data class Address(
       val street: String,
       val city: String
    )
    val (myStreet, myCity) = myAddress
    
    

    目前 Kotlin 使用的基于位置的解构,这存在一定隐患。 比如上述代码,如果某天我们修改了 Address,插入了 postalCode 属性:

    data class Address(
       val street: String,
       val postalCode: String,
       val city: String
    )
    
    

    此时,位置解构中的 myCity 将错误地获取 postalCode 的值,编译器却无法及时发现问题。此外还有一个突出的问题,当 data class 有更多属性时,位置结构只能顺序访问,、无法访问某个指定属性而跳过中间的属性。

    未来 Kotlin 可能会增加基于名字的解构语法:

    val (street = myStreet, city = myCity) = myAddress
    
    

    名字解构中 myCity 中的赋值将不会发生上述错误,而且当有数量众多的属性时也可以更精准地进行赋值。

    异常多重捕获 (Multi catch block)

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

    Java 支持异常多重捕获,即在一个 catch 块中捕获多种异常,而 Kotlin 每个 catch 只能捕获一种异常

    fun loadData(path: String) {
      try {
        findDataLoader(path).loadXmlData()
      }
      catch (e: IOException) {
        println("Failed to load configuration from $path: ${e.message}")
      }
      catch (e: JDOMException) {
        println("Failed to load configuration from $path: ${e.message}")
      }
    }
    
    

    比如上面例子,当我们加载一个 xml 并使用 jdom 对其进行解析时,我们只希望捕获解析相关的错误,忽略其它错误

    fun loadData(path: String) {
      try {
        findDataLoader(path).loadXmlData()
      }
      catch (e: IOException) {
        println("Failed to load configuration from $path: ${e.message}")
      }
      catch (e: JDOMException) {
        println("Failed to load configuration from $path: ${e.message}")
      }
    }
    
    

    上面这样的写法显得比较冗余,即便集中到 when 语句处理也会免不了增加一些模板代码。

    未来 Kotlin 也许会像 Java 那样支持下面这样的写法

    fun loadData(path: String) {
       try {
           findDataLoader(path).loadXmlData()
       } catch (e: IOException | JDOMException) {
           println("Failed to load configuration from $path: ${e.message}")
       }
    }
    
    

    包级访问(Package-private visibility)

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

    Java 中提供了包级访问控制权限,但是 Kotlin 缺少对应的访问控制符。internal 会使得整个 Module 都成为可见范围。 Kotlin 团队认为以前 Package 是划分组件的单元,但如今 Module 成为了更常见的组件粒度,访问权限应该围绕 Module 设计,因此才没有设计包级访问权限。

    虽然这么说有一定道理,但是很多从 Java 转到 Kotlin 的开发者仍然习惯于使用 Package 组织工程,包级访问权限将有助于更好地实现代码隔离,所以不少人仍然希望追加相关能力。

    有人建议使用下面这种语法使 class 访问权限控制在包内

    package com.foo
    import com.foo.detail.*;
    class Public {
       private val impl = Detail()
    }
    // ...
    package com.foo.detail
    private@com.foo class Detail {
    // ...
    
    

    也有人提议通过为 package 引入新的关键字,让 package 内所有的 internal 降级为包内可见。但所有这些方案目前还存在争议,具体方案目前仍然不明朗。

    最后

    上面这些 issue 虽然人气很高,但目前仍处于原型设计和激烈讨论中,未来能否真的出现,以及出现时是否还是这个样子都存在不确定性,不过这也正是 Kotlin 的魅力,所有讨论的过程你都一目了然,甚至参与其中发表你自己的观点和意见。

    为了让大家更快了解和上手 Kotlin,特地分享这份谷歌开源的史上最详Android版kotlin协程入门进阶实战指南,希望可以帮助大家用最短时间学习 Kotlin携程。教程通俗易懂,实例丰富,既有基础知识,也有进阶技能,能够帮助读者快速入门进阶,是你学习Kotlin的葵花宝典,快收藏起来!!!

    第一章 Kotlin协程的基础介绍

    • 1.1 协程是什么
    • 1.2 什么是Job 、Deferred 、协程作用域
    • 1.3 Kotlin协程的基础用法

    第二章 kotlin协程的关键知识点初步讲解

    • 2.1 协程调度器
    • 2.2 协程上下文
    • 2.3 协程启动模式
    • 2.4 协程作用域
    • 2.5 挂起函数

    第三章 kotlin协程的异常处理

    • 3.1 协程异常的产生流程
    • 3.2 协程的异常处理

    第四章 kotlin协程在Android中的基础应用

    • 4.1 Android使用kotlin协程
    • 4.2 在Activity与Framgent中使用协程
    • 4.3 ViewModel中使用协程
    • 4.4 其他环境下使用协程

    第五章 kotlin协程的网络请求封装

    • 5.1 协程的常用环境
    • 5.2 协程在网络请求下的封装及使用
    • 5.3 高阶函数方式
    • 5.4 多状态函数返回值方式
    • 5.5 直接返回值的方式

    第六章 深入kotlin协程原理(一)

    • 6.1 suspend的花花肠子
    • 6.2 藏在身后的-Continuation
    • 6.3 村里的希望-SuspendLambda

    第七章 深入kotlin协程原理(二)

    • 7.1 协程的那些小秘密
    • 7.2 协程的创建过程
    • 7.3 协程的挂起与恢复
    • 7.4 协程的执行与状态机

    第八章 Kotlin Jetpack 实战

    • 8.1 从一个膜拜大神的 Demo 开始
    • 8.2 Kotlin 写 Gradle 脚本是一种什么体验?
    • 8.3 Kotlin 编程的三重境界
    • 8.4 Kotlin 高阶函数
    • 8.5 Kotlin 泛型
    • 8.6 Kotlin 扩展
    • 8.7 Kotlin 委托
    • 8.8 协程“不为人知”的调试技巧
    • 8.9 图解协程原理

    第九章 Kotlin + 协程 + Retrofit + MVVM优雅的实现网络请求

    • 9.1 项目配置
    • 9.2 实现思路
    • 9.3 协程实现
    • 9.4 协程 + ViewModel + LiveData实现
    • 9.5 后续优化
    • 9.6 异常处理

    朋友们如果需要这份完整版的《史上最详Android版kotlin协程入门进阶实战指南》,可点击公众号免费获取】。

    相关文章

      网友评论

          本文标题:预测一下Kotlin未来可能引入的新功能

          本文链接:https://www.haomeiwen.com/subject/fdwrirtx.html