原文链接在我的博客:
前段日子Kotlin
发布了1.0版,号称Android界的Swift,一副拯救苦逼Android码农于水火中的架势。那么它有何神奇之处呢?经过一段时间的摸索,Kotlin在我眼中定位为“通吃型”语言,服务端不是问题,还能生成JavaScript,另外又有针对Android开发的增强服务特性。
Kotlin一出世就被拿来跟Scala比较,恰巧Scala也是我喜欢的一门JVM语言。其实,我个人感觉Kotlin并非Scala的小弟,只是说有了val
和var
的表象,给许多开发者这种感觉,但要这么说的话,Scala的函数/方法定义用def
而Kotlin却用fun
这又怎么说呢?此外,Kotlin的伴生对象跟Scala中的概念也区别不小。另一种说法是Kotlin比Scala简单,也许Kotlin尚未实现Scala中我喜欢的yield
功能,但要从发展角度来看,Kotlin出道时间短,后续要添加的功能应该会层出不穷。Kotlin的用法并不简单。要说“骨子里”的像,我宁愿觉得Kotlin更像Java
:
- 号称“100% interoperable with Java™”:使用一段时间的感受是,写着写着,就有可能不知不觉中无缝地使用Java代码风格,写完了才恍然大悟......
- 一方面Kotlin添加了大量函数式风格,它的map、filter等等操作比
Java 8
Stream的来得简洁直接。但隐约感受得到,这只是Kotlin特性中表面且很小的一部分,涉及过多的功能需求时,还是要寻求Java的特性支持。这点不像Scala,Scala是能不用Java原生特性就不用,而Kotlin则是需要用时你用就是了。不知道这是好事还是坏事,但终究看个人偏好吧,对于Java底子较好或较适应Java风格的开发者来说,这则是一个不错的起点。
上面是我觉得有必要澄清的一些概念。而以下则是Kotlin吸引我研究下去的一些因素:
- Null Safety:别小看这一点,强迫症真能防范大量潜在问题。
- Extension Functions:很喜欢这个特性,即开即用的感觉。
- JetBrains家的东西,还是有些功底的,更重要的是跟闻名遐迩的自家开发工具必然结合紧密。
- 充分考虑Android平台开发的环境及特性适配,也难怪称为“Android开发的Swift”。
- 与Java的互操作性:也许会让大票开发者不感冒,但对我来说再好不过。
以下是Kotlin的一些限制,当然也只是我个人的一些看法:
- 稳定性:尚待提高,特别是REPL工具,动不动就导致退出REPL环境。此外,代码中的空行及注释都会在REPL中引发异常。
- 文档:官方文档比较初级,且资源不多。
- 普及率:小众。TIOBE从上月起已经纳入了Kotlin的观察,首月排名貌似158位。
整个感受,用这个示例实现来解释最恰当不过了:
给一个自定义日期类添加Comparison
、Range
及For
迭代功能。
data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int) : Comparable<MyDate> {
override fun compareTo(other: MyDate): Int {
val calendar1: java.util.Calendar = java.util.Calendar.getInstance()
val calendar2: java.util.Calendar = java.util.Calendar.getInstance()
calendar1.set(this.year, this.month - 1, this.dayOfMonth)
calendar2.set(other.year, other.month - 1, other.dayOfMonth)
return if (calendar1.before(calendar2)) -1 else if (calendar1.after(calendar2)) 1 else 0
}
}
class DateRange(val start: MyDate, val end: MyDate): Iterable<MyDate> {
private var _dateRange: MutableList<MyDate> = mutableListOf<MyDate>()
init {
val calendar1: java.util.Calendar = java.util.Calendar.getInstance()
val calendar2: java.util.Calendar = java.util.Calendar.getInstance()
calendar1.set(start.year, start.month - 1, start.dayOfMonth)
calendar2.set(end.year, end.month - 1, end.dayOfMonth)
if (start < end) {
_dateRange.add(MyDate(calendar1.get(java.util.Calendar.YEAR),
calendar1.get(java.util.Calendar.MONTH) + 1,
calendar1.get(java.util.Calendar.DAY_OF_MONTH)))
val days = (calendar2.getTimeInMillis() - calendar1.getTimeInMillis()) / 1000 / 60 /60 /24
for (day in 1..days) {
calendar1.add(java.util.Calendar.DAY_OF_MONTH, 1)
_dateRange.add(MyDate(calendar1.get(java.util.Calendar.YEAR),
calendar1.get(java.util.Calendar.MONTH) + 1,
calendar1.get(java.util.Calendar.DAY_OF_MONTH)))
}
}
}
override operator fun iterator(): Iterator<MyDate> {
return MyDateIterator()
}
inner class MyDateIterator: Iterator<MyDate> {
private var _index: Int = 0
override operator fun hasNext(): Boolean {
return _index != _dateRange.size
}
override operator fun next(): MyDate {
return _dateRange[_index++];
}
}
}
operator fun MyDate.rangeTo(other: MyDate): DateRange {
return DateRange(this, other)
}
测试代码:
>>> fun iterateOverDateRange(firstDate: MyDate, secondDate: MyDate, handler: (MyDate) -> Unit) {
... for (date in firstDate..secondDate) {
... handler(date)
... }
... }
>>> iterateOverDateRange(MyDate(2016, 3, 10), MyDate(2016, 3, 14)) { println(it) }
MyDate(year=2016, month=3, dayOfMonth=10)
MyDate(year=2016, month=3, dayOfMonth=11)
MyDate(year=2016, month=3, dayOfMonth=12)
MyDate(year=2016, month=3, dayOfMonth=13)
MyDate(year=2016, month=3, dayOfMonth=14)
>>> iterateOverDateRange(MyDate(2016, 5, 1), MyDate(2016, 5, 5)) { println(it) }
MyDate(year=2016, month=5, dayOfMonth=1)
MyDate(year=2016, month=5, dayOfMonth=2)
MyDate(year=2016, month=5, dayOfMonth=3)
MyDate(year=2016, month=5, dayOfMonth=4)
MyDate(year=2016, month=5, dayOfMonth=5)
>>> iterateOverDateRange(MyDate(2016, 5, 1), MyDate(2016, 5, 1)) { println(it) }
>>> (MyDate(2016, 3, 10)..MyDate(2016, 3, 14)).map { println("${it.year}-${it.month}-${it.dayOfMonth}") }
2016-3-10
2016-3-11
2016-3-12
2016-3-13
2016-3-14
[kotlin.Unit, kotlin.Unit, kotlin.Unit, kotlin.Unit, kotlin.Unit]
>>>
>>> fun checkInRange(date: MyDate, first: MyDate, last: MyDate): Boolean {
... return date in first..last
... }
>>> checkInRange(MyDate(2016, 3, 13), MyDate(2016, 3, 10), MyDate(2016, 3, 14))
true
>>> checkInRange(MyDate(2016, 3, 8), MyDate(2016, 3, 10), MyDate(2016, 3, 14))
false
>>> checkInRange(MyDate(2015, 3, 13), MyDate(2016, 3, 10), MyDate(2016, 3, 14))
false
>>>
结论:
刚好现在看到一个开发者的困惑:“Kotlin让我感到不安。它离开Java 能玩得起吗 ?”我觉得Kotlin发展的前提是不离开Java,这个前提没了,估计Scala、Clojure一样没戏——Kotlin本身就是Java形态的增强与补充!
该不该学习Kotlin?——Kotlin就是一门语言,不是什么“十全大补丸”,但其现在面临的最急迫任务就是普及与推广,至少要达到Groovy、Scala或Clojure等“同门师兄弟”的地位,虽然这些个JVM语言的排名也不是很高。“该不该学”这个问题真没有答案。总之,它就是一门新兴的语言而已。