问题描述
我很好奇在Kotlin中定义成员函数的建议方法是什么.考虑以下两个成员函数:
I'm curious about what is the suggested way to define member functions in Kotlin. Consider these two member functions:
class A {
fun f(x: Int) = 42
val g = fun(x: Int) = 42
}
这些似乎可以完成相同的任务,但是我发现了细微的差别.
These appear to accomplish the same thing, but I found subtle differences.
例如,基于val
的定义在某些情况下似乎更灵活.也就是说,我无法找到一种直接的方法来将f
与其他功能组合在一起,但是我可以与g
组合在一起.为了弄清楚这些定义,我使用了 funKTionale 库.我发现它无法编译:
The val
based definition, for instance, seems to be more flexible in some scenarios. That is, I could not work out a straight forward way to compose f
with other functions, but I could with g
. To toy around with these definitions, I used the funKTionale library. I found that this does not compile:
val z = g andThen A::f // f is a member function
但是,如果将f
定义为指向同一函数的val
,它将可以正常编译.为了弄清楚发生了什么,我要求IntelliJ为我显式定义::f
和g
的类型,这给了我这个:
But if f
were defined as a val
pointing to the same function, it would compile just fine. To figure out what was going on I asked IntelliJ to explicitly define the type of ::f
and g
for me, and it gives me this:
val fref: KFunction1<Int, Int> = ::f
val gref: (Int) -> Int = g
因此,一个类型为KFunction1<Int, Int>
,另一个类型为(Int) -> Int
.显而易见,这两个函数都代表类型为Int -> Int
的函数.
So one is of type KFunction1<Int, Int>
, the other is of type (Int) -> Int
. It's easy to see that both represent functions of type Int -> Int
.
这两种类型有什么区别,在什么情况下重要?我注意到,对于顶层函数,我可以使用任何一种定义对其进行精细组合,但是为了使上述组合得以编译,我必须像这样编写它:
What is the difference between these two types, and in which cases does it matter? I noticed that for top-level functions, I can compose them fine using either definition, but in order to make the aforementioned composition compile, I had to write it like so:
val z = g andThen A::f.partially1(this)
即我必须先将其部分应用于this
.
i.e. I had to partially apply it to this
first.
由于使用val
作为函数时不必麻烦,所以有理由为什么我应该使用fun
定义非Unit成员函数吗?我缺少的性能或语义上有区别吗?
Since I don't have to go through this hassle when using val
s for functions, is there a reason why I should ever define non-Unit member functions using fun
? Is there a difference in performance or semantics that I am missing?
推荐答案
Kotlin完全是关于Java互操作性的,将函数定义为val
会在互操作性方面产生完全不同的结果.以下Kotlin类:
Kotlin is all about Java interoperability and defining a function as a val
will produce a completely different result in terms of the interoperability. The following Kotlin class:
class A {
fun f(x: Int) = 42
val g = fun(x: Int) = 42
}
实际上等效于:
public class A {
private final Function1<Integer, Integer> gref = new Function1<Integer, Integer>() {
@Override
public Integer invoke(final Integer integer) {
return 42;
}
};
public int f(final int value) {
return 42;
}
public Function1<Integer, Integer> getG() {
return gref;
}
}
如您所见,主要区别在于:
As you can see, the main differences are:
-
fun f
只是一种常用方法,而val g
实际上是一个高阶函数,它返回另一个函数 -
val g
涉及创建一个新类,如果您以Android为目标,那么这是不好的 -
val g
需要不必要的装箱和拆箱 -
val g
不能从Java轻松调用:Kotlin中的A().g(42)
与Java中的new A().getG().invoke(42)
fun f
is just a usual method, whileval g
in fact is a higher-order function that returns another functionval g
involves creation of a new class which isn't good if you are targeting Androidval g
requires unnecessary boxing and unboxingval g
cannot be easily invoked from java:A().g(42)
in Kotlin vsnew A().getG().invoke(42)
in Java
更新:
关于A::f
语法.编译器将为每次 A::f
事件生成一个额外的Function2<A, Integer, Integer>
类,因此以下代码将生成两个额外的类,每个类具有 7个方法:
Regarding the A::f
syntax. The compiler will generate an extra Function2<A, Integer, Integer>
class for every A::f
occurrence, so the following code results in two extra classes with 7 methods each:
val first = A::f
val second = A::f
Kotlin编译器目前不足以优化此类内容.您可以在此处对此问题进行投票 https://youtrack.jetbrains.com/issue/KT-9831 .如果您感兴趣,以下是每个类在字节码中的显示方式: https://gist.github .com/nsk-mironov/fc13f2075bfa05d8a3c3
Kotlin compiler isn't smart enough at the moment to optimize such kind of things. You can vote for the issue here https://youtrack.jetbrains.com/issue/KT-9831. In case you are interested, here is how each class looks in the bytecode: https://gist.github.com/nsk-mironov/fc13f2075bfa05d8a3c3
这篇关于函数定义:fun vs val的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!