【读书笔记】《Kotlin in Action》学习笔记(下)
一、前言
读书笔记的上部分请参考:【读书笔记】《Kotlin in Action》学习笔记(上)
另外,关于我在 mobilehub 微信留言中免费获赠中文版《 Kotlin 实战》书籍的留言我也贴上,当时我回答的时候一方面想着能意外收获一本书,另一方面还是非常想推荐这边书给读者朋友们!
二、笔记
1、 操作符重载要注意的
a += b
与a = a.plus(b)
或者a.plusAssign(b)
两者都完全等同( + - * / % 一样)
1 | val list = arrayListOf(1, 2) |
- 如果
plus
和plusAssign
两个都有定义,参数也一样,那么会出现编译模糊问题( + - * / % 一样)
1 | data class Point(var x:Int = 0, var y:Int = 0) { |
上面的代码很显然是没问题的,注意 val
变量不能赋值。但是,如果添加下面的代码( 通过扩展给 Point
类新增 plusAssign
方法)就是画蛇添足,会出现问题:
1 | operator fun Point.plusAssign(otherPoint:Point) { |
- 把上面的 plusAssign 方法签名(参数类型)改一下可以使用,但意义已经改变
1 | operator fun Point.plusAssign(otherInt:Int) { |
2、 型变和协变( in 和 out )参数在构造函数中不受约束
这又是一个特例!我们知道,使用 in 的参数是不能作为输出返回的,而使用 out 则作为输出而不能作为参数传入,下面两个接口就是这样,弄反了就出问题:
1 | interface IOutParameter<out T> { |
再看类的构造函数,这是不受形参限制的,注意参数的位置:
1 | // Note that constructor parameters are in neither the [in] nor [out] position. |
3、 使用形参的一个正确姿势
这是一个非常简单的问题,对于大部分人来说,由于缺乏经验,我把这一条也作为书签记录下来,提醒自己可以如何优化(下面是官方例子)。首先看原始版本,拷贝一个列表到另一个:
1 | fun <T> copyDataVersion1(source: MutableList<T>, destination: MutableList<T>) { |
上面的代码其实不合理(后面有说明),难道一定要同类型才能复制吗? T
的子类不能被复制过去吗?那么根据这个问题有了下面的改进:
1 | fun <T: R, R> copyDataVersion2(source: MutableList<T>, destination: MutableList<R>) { |
上面的代码搞定了子类的数据复制,到此结束!?当然没有, Kotlin 提供了一个更加优雅的解决方案,不信你看看下面的代码:
1 | fun <T> copyDataVersion3(source: MutableList<out T>, destination: MutableList<T>) { |
什么叫做优化?什么叫做改进?学习了!下面是测试代码:
1 | fun main(vararg parameters:String) { |
4、 Kotlin 中 DSL 使用带有 object 参数的中缀函数
我只想说,“厉害了,我的 Kotlin 哥”! Kotlin 中 DSL 真的很好用,像大名鼎鼎的 anko 库,使用 DSL 实现 Android Layout 非常给力啊,还有 SQL 数据库操作,另外用过一段时间的 TornadoFX ,用 DSL 写 GUI 程序也是给力极了!
看下面一句话,还是来自教材:
1 | "kotlin" should start with "kot" |
Sorry ,说错了,不是一句话,是一段代码!对,这段代码没啥稀奇的了,不就是中缀函数拼凑起来吗?
1 | "kotlin".should(start).with("kot") |
没错,但是他的精髓你发现了没?精髓在于 start
的妙用!它是一个 object
单例,那么既然是单例为啥不直接使用,还要去作为 should
函数的参数呢?这不是毫无意义吗? No !这是 DSL 哦,它并不是作为数据参数传递给函数,而是作为语法的一部分!!!因此你可以有很多 object
,作为不同的语法使用,这就是精髓之处啊!
我相信,看了下面的代码你就能一目了然、豁然开朗了!
1 | object start |
激动的我赶紧写下了几行流利的英语:
1 | "kotlin" should start with "kot" |
5、 Bonus: 使用 inline 属性
对,你没看错,这是额外加的一个新姿势,并不是从《 Kotlin in Action 》书中学到的,看到了我就马上记下来了,写到一起作为学习笔记吧。
参考以下代码,扩展一个属性非常简单:
1 | inline var View.isVisible |
毫无疑问代码是没有问题的,那么我们看下反编译 Kotlin 后的 Java 代码(无关省略):
1 | if(GlobalKt.isVisible((View)button)) { |
很正常啊, Kotlin 的风格,使用静态方法完成扩展呀。但是,我就是没想到为啥不用 inline 呢?省去静态方法,不是更快更方便吗?
1 | val View.isVisible |
反编译后:
1 | View $receiver$iv = (View)button; |
是不是更加得体了呢?反正我是这么认为的,省去了没必要的静态类方法。另外, inline 也可以写得更加优雅,也有需要注意的地方哦:
1 | inline val View.isVisible |
更多可以参考原文: Inlining Kotlin Properties
三、完