网友提议为 Kotlin 引入这些新特性 …

前言

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

网友提议为 Kotlin 引入这些新特性 ...YouTrack Hot Issue

透过 YouTrack 中当下的热门 issue ,我们可以预见 Kotlin 未来有可能引入下面这些新特性:

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

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

命名空间 (Namespace)

https://youtrack.jetbrains.com/issue/KT-11968

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)

https://youtrack.jetbrains.com/issue/KT-10468

有时我们会在 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)

https://youtrack.jetbrains.com/issue/KT-43871

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

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

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

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

val list = [123// 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> = [123// creates a Set<Int> 
val map: MutableMap<String, Int> = ["one"1"two"2"three"3// creates a MutableMap

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

val array = Array [123// creates Array<Int>, note that "Int" was inferred here

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

data class Point(val x: Intval y: Int)
fun drawLine(from: Point, to: Point)

// Normal Calling
drawLine(Point(12), Point(34))
// Calling with Collection literals
drawLine([12], [34])

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

https://youtrack.jetbrains.com/issue/KT-14663

我们经常有这种需求:一个类的属性对内使用 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)

https://youtrack.jetbrains.com/issue/KT-19627

我们在访问 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)

https://youtrack.jetbrains.com/issue/KT-7128

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)

https://youtrack.jetbrains.com/issue/KT-29227

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 引入这些新特性 ...
END


推荐文章 


网友提议为 Kotlin 引入这些新特性 ...
 
网友提议为 Kotlin 引入这些新特性 ...
加好友进群,技术聊不停

网友提议为 Kotlin 引入这些新特性 ...


原文始发于微信公众号(AndroidPub):网友提议为 Kotlin 引入这些新特性 …

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/57454.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!