
作为一个 javer 当我看到类似这样的代码的时候,我的内心还是有小小的震撼的。
val someday = "today" afterDay 4
当看到这段代码的时候,你有没有懵逼掉?
today 后面没有 . 却是出现了一个 afterDay 这个莫名其妙的东西那我们看看他是怎么实现的了!
在写出上述代码之前我们需要了解一个 Java 中没有的东西,那就是 扩展函数 。
扩展函数的重点就是“扩展”,它扩展的就是某个类的方法、属性等,可以为原本不存在于某个类的方法和属性做扩展。
我们来举 2 个例子,比如对于 String 期望能有一个 join 将字段拼接起来,
val res = "123".append("abc")//结果是123abc
但是 JDK 中的 String 中没有这个 append 方法,同时这个 String 是 JDK 的包,我们也没有很好的办法去修改源码,那么此时扩展函数的作用就来了。
fun String.append(that: String): String {
return this + that
}
上面的就是扩展函数
String.append 表示的就是为 String 这个类扩展 append 这个方法(that:String) 就是一个形参上面的例子很好理解了吧?
对于某个字符串,我们希望他有个 属性 (注意不是方法),比如 a 出现的次数 aTimes
假如 aTimes 是一个方法,可以这么实现
fun String.aTimes(): Int {
return this.toCharArray().filter { it == 'a' }.count()
}
假如 aTimes 是一个 只读属性 ,那么如何实现?
val String.aTimes: Int
get() = this.toCharArray().filter { it == 'a' }.count()
val 修饰 只读属性get() 方法: 后的是获取的类型那么假如某个属性,既是 能读又能写 的,如何实现了?
var StringBuilder.lastChar: Char
get() = get(length - 1)
set(value) {
this.setCharAt(length -1, value)
}
var 修饰: 后的是获取和设置的类型。当我们有了上述基础后,我们就来看看 中缀表达式 的实现。
kotlin 中有一个关键字叫做 infix ,很多翻译叫做 中缀表达式 ,我们就先这么称呼着,名字而已,约定俗成。
我们先回顾下文章最先出现的代码:
val someday = "today" afterDay 4
假如 afterDay 是点出来的方法,我们都可以对他进行实现了,比如说
fun String.afterDay(offset: Int): LocalDate {
return when (this) {
"today" -> LocalDate.now().plusDays(offset.toLong())
//省略其他
else -> throw IllegalArgumentException("参数不合法")
}
}
//调用的时候可以
val someDay = "toDay".afterDay(4)
但是我们想要的不是 . 出来的,而是把除 . 和 () 这些符号去掉,只保留最核心的元素。
其实通过 infix 可以很简答的实现
//中缀表达式:用于两个对象间的运算
infix fun String.afterDay(that: Int): LocalDate {
return when (this) {
"today" -> LocalDate.now().plusDays(that.toLong())
"yesterday" -> LocalDate.now().plusDays(that.toLong() - 1)
"tomorrow" -> LocalDate.now().plusDays(that.toLong() + 1)
else -> LocalDate.now().plusDays(that.toLong())
}
}
//这样调用
val someday = "today" afterDay 4
上述代码中只是加了关键字 infix ,那么就可以不通过 . 来调用方法,而是通过 空格+方法名 的形式调用。
从本质上来说,其实这些都是语法糖,掌握了这些语法糖,当你在可能使用到的地方,确实是有点 甜