Kotlin – 函数的调用操作符重载

我正在学习Kotlin – 运算符重载
我想了解(例如)运算符重载如何为函数的invoke()函数工作

预先测试

  • Kotlin的扩展函数

     fun exampleOfExtensionFunction() { fun Int.randomize(): Int { return Random(this.toLong()).nextInt() } val randomizedFive = 5.randomize() println("$randomizedFive") } 

    打印:

    -1157408321

  • 在Kotlin中,函数可以用types声明为variables

     fun exampleOfFunctionType() { val printNumber: (number: Int) -> Unit printNumber = { number -> println("[$number = ${number.toString(16).toUpperCase()} = ${number.toString(2)}]") } printNumber(1023) } 

    打印:

    [1023 = 3FF = 1111111111]

  • Kotlin允许运算符用扩展和成员函数重载

     fun exampleOfOperatorOverloadingUsingExtensionFunction() { class MyType() { val strings: ArrayList = ArrayList() override fun toString(): String { val joiner: StringJoiner = StringJoiner(" , ", "{ ", " }") for (string in strings) { joiner.add("\"$string\"") } return joiner.toString() } } operator fun MyType.contains(stringToCheck: String): Boolean { for (stringElement in strings) { if (stringElement == stringToCheck) return true } return false } val myType = MyType() myType.strings.add("one") myType.strings.add("two") myType.strings.add("three") println("$myType") println("(myType.contains(\"four\")) = ${myType.contains("four")} , (\"three\" in myType) = ${"three" in myType}") } 

    打印:

    { “一二三” }
    (myType.contains(“four”))= false,(myType中的“three”)= true

测试尝试
基于以上。 我试图用扩展函数invoke(flag1: Boolean, flag2: Boolean, flag3: Boolean)的types(Boolean, Boolean, Boolean) -> Boolean作为接收器types来创建函数的invoke()运算符重载invoke(flag1: Boolean, flag2: Boolean, flag3: Boolean) 。 然而,这并没有如预期的那样工作。

  fun attemptFunctionInvokeOperatorOverloading() { operator fun ((Boolean, Boolean, Boolean) -> Boolean).invoke(flag1: Boolean, flag2: Boolean, flag3: Boolean): Boolean { println("Overloaded invoke operator") return flag1 && flag2 && flag3 } var func1: ((Boolean, Boolean, Boolean) -> Boolean) = { flag1, flag2, flag3 -> println("func1 body") flag1 && flag2 && flag3 } fun func2(flag1: Boolean, flag2: Boolean, flag3: Boolean): Boolean { println("func2 body") return flag1 && flag2 && flag3 } func1(true, true, false) func2(true, true, true) } 

打印:

func1身体
func2的身体

预期:

重载的调用操作符
重载的调用操作符

另一个问题
这究竟是什么? (如果不是运营商超载)

  operator fun ((Boolean, Boolean, Boolean) -> Boolean).invoke(flag1: Boolean, flag2: Boolean, flag3: Boolean): Boolean { println("Overloaded invoke operator") return flag1 && flag2 && flag3 } 

正如在另一个答案中所说的,invoke是在函数对象本身上定义的,所以你不能用扩展方法来覆盖它。

我认为这里的更深层次的问题是对这个function目的的轻微误解。 我们来看看+运算符的plus

我认为你会同意尝试定义fun Int.plus(b: Int): Int { /* ... */}是没有意义的,因为重写默认的+运算符是一个非常危险的事情,是?

但是,如果您定义了一个复数类:

 data class Complex(real: Double, img: Double) 

那么定义这个总和复数是完全合理的:

 fun Complex.plus(other: Complex): Complex { val real = this.real + other.real val img = this.img + other.img return Complex(real, img) } 

因此,与invoke()相同的事情()的含义是,无论类似于为你的types调用一个函数,重写invoke已经是函数的东西,只是要求麻烦。 你想用它来代替是为你自己的对象提供函数式的语法。

例如,假设你像这样定义一个接口:

 interface MyCallback { fun call(ctx: MyContext) } 

你用哪种方式:

 callback.call(ctx) 

但是通过invoke运算符重载的实现,您可以将其用作函数:

 fun MyCallback.invoke(ctx: Context) = this.call(ctx) /* Elsewhere... */ callback(ctx) 

希望澄清你如何使用invoke / ()

您的问题必须以解决方案优先。 根据Kotlin文档 :

如果一个类有一个成员函数,并且定义了一个具有相同接收器types,相同名称并适用于给定参数的扩展函数,则该成员总是获胜

因此,您的operator fun ((Boolean, Boolean, Boolean) -> Boolean).invoke(...)扩展函数永远不会被调用,因为成员invoke优先。

另一个答案

这确实是运营商超载,但通过扩展。 同样,因为(Boolean, Boolean, Boolean) -> Boolean已经有一个fun invoke(Boolean, Boolean, Boolean): Boolean定义,您的扩展失去。