我很好奇在Kotlin中定义成员函数的建议方法是什么 . 考虑这两个成员函数:
class A {
fun f(x: Int) = 42
val g = fun(x: Int) = 42
}
这些似乎完成了同样的事情,但我发现了微妙的差异 .
例如,基于 val
的定义在某些情况下似乎更灵活 . 也就是说,我无法用一种直接的方式来编写 f
与其他函数,但我可以用 g
. 为了玩弄这些定义,我使用了funKTionale库 . 我发现这不编译:
val z = g andThen A::f // f is a member function
但是如果将 f
定义为指向同一函数的 val
,那么编译就可以了 . 为了弄清楚发生了什么,我让IntelliJ为我明确定义了 ::f
和 g
的类型,它给了我这个:
val fref: KFunction1<Int, Int> = ::f
val gref: (Int) -> Int = g
所以一个是 KFunction1<Int, Int>
类型,另一个是 (Int) -> Int
类型 . 很容易看出它们都代表 Int -> Int
类型的函数 .
这两种类型有什么区别,哪种情况重要?我注意到对于顶级函数,我可以使用任何一个定义来组合它们,但是为了使前面的组合编译,我必须这样写:
val z = g andThen A::f.partially1(this)
即我必须首先将其部分应用于 this
.
因为在使用 val
来执行函数时我不必经历这种麻烦,所以我有理由使用 fun
来定义非单元成员函数吗?我缺少的性能或语义是否存在差异?
2 回答
Kotlin是关于Java互操作性的,并且定义一个函数作为
val
将在互操作性方面产生完全不同的结果 . 以下Kotlin课程:实际上相当于:
如您所见,主要区别在于:
fun f
只是一种常用的方法,而val g
实际上是一个返回另一个函数的高阶函数val g
涉及创建一个新类,如果你的目标是Android,那就不好了val g
需要不必要的装箱和拆箱无法从java轻松调用
val g
:Kotlin中的A().g(42)
与Java中的new A().getG().invoke(42)
UPDATE:
关于
A::f
语法 . 编译器将为 everyA::f
事件生成一个额外的Function2<A, Integer, Integer>
类,因此以下代码会产生两个额外的类,每个类具有 7 methods :Kotlin编译器目前还不够聪明,无法优化此类事物 . 你可以在这里https://youtrack.jetbrains.com/issue/KT-9831投票支持这个问题 . 如果您感兴趣,以下是每个类在字节码中的显示方式:https://gist.github.com/nsk-mironov/fc13f2075bfa05d8a3c3
这里有一些代码显示了f和g在使用方面的不同之处:
你可以看到g是一个可以像lambda一样使用的对象,但f不能 . 要类似地使用f,你必须将它包装在lambda中 .