[英]Function definition: fun vs val
I'm curious about what is the suggested way to define member functions in Kotlin. 我很好奇在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. 这些似乎完成了同样的事情,但我发现了微妙的差异。
The val
based definition, for instance, seems to be more flexible in some scenarios. 例如,基于
val
的定义在某些情况下似乎更灵活。 That is, I could not work out a straight forward way to compose f
with other functions, but I could with g
. 也就是说,我无法通过直接的方式将
f
与其他函数组合起来,但我可以用g
。 To toy around with these definitions, I used the funKTionale library. 为了玩弄这些定义,我使用了funKTionale库。 I found that this does not compile:
我发现这不编译:
val z = g andThen A::f // f is a member function
But if f
were defined as a val
pointing to the same function, it would compile just fine. 但是如果
f
被定义为指向同一函数的val
,那么编译就好了。 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: 为了弄清楚发生了什么,我要求IntelliJ为我明确定义
::f
和g
的类型,它给了我:
val fref: KFunction1<Int, Int> = ::f
val gref: (Int) -> Int = g
So one is of type KFunction1<Int, Int>
, the other is of type (Int) -> Int
. 所以一个是
KFunction1<Int, Int>
类型,另一个是类型(Int) -> Int
。 It's easy to see that both represent functions of type Int -> Int
. 很容易看出它们都代表
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)
ie I had to partially apply it to this
first. 即我必须首先将其部分应用于
this
。
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
? 因为在使用
val
s作为函数时我不必经历这种麻烦,所以我有理由使用fun
定义非Unit成员函数吗? Is there a difference in performance or semantics that I am missing? 我缺少的性能或语义是否存在差异?
Kotlin is all about Java interoperability and defining a function as a val
will produce a completely different result in terms of the interoperability. Kotlin完全关注Java互操作性,将函数定义为
val
将在互操作性方面产生完全不同的结果。 The following Kotlin class: 以下Kotlin类:
class A {
fun f(x: Int) = 42
val g = fun(x: Int) = 42
}
is effectively equivalent to: 实际上相当于:
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
is just a usual method, while val g
in fact is a higher-order function that returns another function fun f
只是一种常用方法,而val g
实际上是一个返回另一个函数的高阶函数 val g
involves creation of a new class which isn't good if you are targeting Android val g
涉及创建一个新类,如果你的目标是Android,那就不好了 val g
requires unnecessary boxing and unboxing val g
需要不必要的装箱和拆箱 val g
cannot be easily invoked from java: A().g(42)
in Kotlin vs new A().getG().invoke(42)
in Java val g
不能从java中轻松调用:Kotlin中的A().g(42)
vs Java中的new A().getG().invoke(42)
UPDATE: 更新:
Regarding the A::f
syntax. 关于
A::f
语法。 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: 编译器将为每个
A::f
出现一个额外的Function2<A, Integer, Integer>
类,因此以下代码会产生两个额外的类,每个类有7个方法 :
val first = A::f
val second = A::f
Kotlin compiler isn't smart enough at the moment to optimize such kind of things. Kotlin编译器目前还不够聪明,无法优化此类事物。 You can vote for the issue here https://youtrack.jetbrains.com/issue/KT-9831 .
您可以在此处投票支持此问题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
如果您感兴趣,以下是每个类在字节码中的显示方式: https : //gist.github.com/nsk-mironov/fc13f2075bfa05d8a3c3
Here's some code showing how f and g are different when it comes to usage: 这里有一些代码显示f和g在使用方面有何不同:
fun main(args: Array<String>) {
val a = A()
exe(a.g) // OK
//exe(a.f) // does not compile
exe { a.f(it) } // OK
}
fun exe(p: (Int) -> Int) {
println(p(0))
}
Where f
and g
are: 其中
f
和g
是:
fun f(x: Int) = 42
val g = fun(x: Int) = 42
You can see that g is an object that can be used like a lambda, but f cannot. 你可以看到g是一个可以像lambda一样使用的对象,但f不能。 To use f similarly, you have to wrap it in a lambda.
要类似地使用f,你必须将它包装在lambda中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.