最近在 portal.kotlin-academy.com/#/ 上看到很多关于 Kotlin 的有趣的题目。个人觉得很适合 Kotlin 爱好者,感兴趣的小伙伴可自行查阅。
【有趣的 Kotlin 】系列记录自己对每一题的理解。
0x0A:Fun with composition
val increment = { i: Int -> i + 1 }
val bicrement = { i: Int -> i + 2 }
val double = { i: Int -> i * 2 }
val one = { 1 }
infix fun <T, R> (() -> T).then(another: (T) -> R) = { another(this()) }
operator fun <T, R1, R2> ((T) -> R1).plus(another: (T) -> R2) = { x: T -> this(x) to another(x) }
fun main(args: Array<String>) {
val equilibrum = one then double then (increment + bicrement)
print(equilibrum())
}
以上代码,运行结果是什么?可选项:
- Nothing, it doesn't compile
- 5
- (1,2)
- (3,4)
思考一下,记录下你心中的答案。
分析
先看看变量
题目开头定义 4 个变量,皆为 函数类型和 Lambda 表达式。
函数用途:
- increment:加 1
- bicrement:加 2
- double:加倍
- one:调用后返回数值 1
再看看函数
4 个变量后,紧跟 2 个函数,一个是中缀函数,一个是操作符重载函数。
then
:串联两个函数。先执行receiver
,结果作为参数传入another
。plus
:合并两个函数的结果。执行receiver
,执行another
,并将两个结果组成Pair
。
中缀函数 then
then
函数是一个中缀函数,同时也是一个泛型函数,持有 T
, R
两种泛型类型
- receiver:
() -> T
。 - 参数:
(T) -> R
。 - 返回值:
() -> R
。
使用 infix
修饰的函数为 中缀函数,必须满足三个条件:
- 必须是成员函数或扩展函数。
- 必须有唯一的函数参数。
- 参数不可为可变数量的参数 (vararg ),并且不能有默认值。
infix fun Int.shl(x: Int): Int { ... }
// calling the function using the infix notation
1 shl 2
// is the same as
1.shl(2)
操作符重载函数 plus
plus
是一个操作符重载函数,同时也是一个泛型函数,持有 T
, R1
,R2
三种泛型类型。
- receiver:
(T) -> R1
。 - 参数:
(T) -> R2
。 - 返回值:
(T) -> Pair<R1, R2>
。
最后看主逻辑
fun main(args: Array<String>) {
val equilibrum = one then double then (increment + bicrement)
println(equilibrum())
}
代码逻辑还原一下
所以,最后 println(equilibrum())
执行函数类型变量equilibrum
调用逻辑,并打印结果。
Pair
类型的 toString()
方法 public override fun toString(): String = "($first, $second)"
。
所以,正确答案为 :
选项 4 :(3,4)
总结
语法糖的魅力在于用简洁的代码表达丰富的逻辑。但是反向思考一下,也有可能使逻辑变得晦涩难懂。
所以,日常开发中,选用合适的变量名和函数尤为重要。题中变量名和函数名使用很恰当,1 先加倍,再分别加 1,加 2,最后用 +
代表组合。
val equilibrum = one then double then (increment + bicrement)
\