Kotlin 学习笔记,2020-06-19

上期笔记


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  TreeNode.findParentOfType(clazz: Class): 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  TreeNode.findParentOfType(): T? {
    var p = parent
    while (p != null && p !is T) {
        p = p.parent
    }
    return p as T?
}
...
treeNode.findParentOfType()

这个漂亮多了!但是堵心的是这个特性必须搭配 inline 一起用 …… 好吧从实现角度想了一下,可以理解 …… 但还是很堵心!设计门新语言了都!还非要去学 Java 用 type erasure 做甚!JVM 不提供支持怎么了?自己做 name mangling 搞不定吗?你都在编译器上玩这么多花活了!嗯 …… 好吧二进制分发,我知道了 …………

你可能感兴趣的:(Kotlin 学习笔记,2020-06-19)