函数定义:fun vs val

我很好奇在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为我明确定义了::fg的类型,它给了我这个:

 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) 

即我必须首先部分应用它。

因为在使用val函数的时候,我不必经历这个麻烦,所以我有理由用fun定义非单元成员函数吗? 我缺少性能或语义上的差异吗?

Kotlin完全是关于Java的互操作性,并且定义一个函数作为一个val将在互操作性方面产生一个完全不同的结果。 以下Kotlin类:

 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; } } 

正如你所看到的,主要的区别是:

  1. fun f只是一个常用的方法,而val g实际上是一个返回另一个函数的高阶函数
  2. val g涉及创建一个新的类,如果你的目标是Android,那就不好了
  3. val g需要不必要的装箱和拆箱
  4. val g不能轻易地从java: A().g(42) in Kotlin vs new A().getG().invoke(42) in Java

更新:

关于A::f语法。 编译器会为 A::f发生一个额外的Function2<A, Integer, Integer>类,所以下面的代码会产生两个额外的类,每个类有7个方法

 val first = A::f val second = A::f 

Kotlin编译器目前还不够聪明,以优化这种类型的东西。 你可以在这里为这个问题投票https://youtrack.jetbrains.com/issue/KT-9831 。 如果你有兴趣,这里是每个类在字节码中的外观: https : //gist.github.com/nsk-mironov/fc13f2075bfa05d8a3c3

下面是一些代码,说明如何使用f和g:

 fun main(args: Array<String>) { val a = A() exe(ag) // OK //exe(af) // does not compile exe { af(it) } // OK } fun exe(p: (Int) -> Int) { println(p(0)) } 

你可以看到g是一个可以像lambda一样使用的对象,但是f不能。 要同样使用f,你必须用lambda包装它。