https://kotlinlang.org/docs/reference/functions.html#functions
看了看,没有什么意外,不过有几条想说的。
首先函数最后一个参数如果是 lambda 类型,调用时候有个特殊语法:
fun foo(bar: Int = 0, baz: Int = 1, qux: () -> Unit) { /*...*/ }
foo(1) { println("hello") } // Uses the default value baz = 1
foo(qux = { println("hello") }) // Uses both default values bar = 0 and baz = 1
foo { println("hello") } // Uses both default values bar = 0 and baz = 1
坦率讲我不太喜欢这个,多一种不同的语法,但没看出来有什么价值,白白增加的复杂。另外中缀调用形式我也觉得加上去得不偿失。最后还要吐槽这个尾递归:浪费一个关键字也就算了,关键是我试了一下,一个完全不能尾递归的函数、甚至完全不是递归的函数也可以加这个 tailrec
关键字,而且编译不报错 —— 这种「单纯是个 hint」的特性,你们在 C++ 历史上苦头还没吃够么?
不过这个设计我还挺喜欢的:如果不是可以用一个表达式表示的函数,必须显示指明返回类型。理由说的很好:函数体如果带控制流逻辑,不论是读代码的人还是编译器推断返回类型可能都有困难。某些语言比如 Haskell,就是在这里走过头了。
https://kotlinlang.org/docs/reference/lambdas.html#higher-order-functions-and-lambdas
没有什么意外的一节。函数最后一个参数是 lambda 时的特殊语法之前应该已经吐槽过了,不过这里给出了一个为什么要支持这个语法的理由:可以写 LINQ-style 的代码!
strings.filter { it.length == 5 }.sortedBy { it }.map { it.toUpperCase() }
首先抄袭 C# 实锤到不能再实锤了,然后 TMD 这个语法和下面这个有多大区别?
strings.filter({ it.length == 5 }).sortedBy({ it }).map({ it.toUpperCase() })
然后也和当年的 C# 一样,创建匿名函数支持两套语法,「lambda 表达式风格」和「匿名函数风格」:
val x = fun(x: Int, y: Int): Int { return x + y } // 风格一
val y = { x:Int, y: Int -> x + y} // 风格二
…… 坦率讲当年我就很讨厌 C# 这么做,现在更讨厌了 ……
https://kotlinlang.org/docs/reference/inline-functions.html#inline-functions
在 JVM 上跑的语言会有这个显示指定 inline 的支持,我便是没想到。更没想到的是还有对应的 noinline ……
但这一节里面介绍的 Reified type parameter 是个有用的特性。2020-06-18 的笔记 里有提到这个关键字,没想到解释在这里(而且为什么会在这里?不应该放泛型那一节吗?)。简单讲就是 Java 风格的泛型中一个让我讨厌了很久的「整天要给泛型函数传 clazz
」问题得到了缓解:
fun <T> TreeNode.findParentOfType(clazz: Class<T>): T? {
var p = parent
while (p != null && !clazz.isInstance(p)) {
p = p.parent
}
@Suppress("UNCHECKED_CAST")
return p as T?
}
...
treeNode.findParentOfType(MyTreeNode::class.java)
// 可以变化为
inline fun <reified T> TreeNode.findParentOfType(): T? {
var p = parent
while (p != null && p !is T) {
p = p.parent
}
return p as T?
}
...
treeNode.findParentOfType<MyTreeNode>()
这个漂亮多了!但是堵心的是这个特性必须搭配 inline 一起用 …… 好吧从实现角度想了一下,可以理解 …… 但还是很堵心!设计门新语言了都!还非要去学 Java 用 type erasure 做甚!JVM 不提供支持怎么了?自己做 name mangling 搞不定吗?你都在编译器上玩这么多花活了!嗯 …… 好吧二进制分发,我知道了 …………