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

Ser*_*ero 3 operator-overloading kotlin

我正在学习Kotlin - 运算符重载
我试图理解(有一个例子)运算符重载如何为函数的invoke()函数工作

预测试

  • Kotlin的扩展功能

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

    印刷品:

    -1157408321

  • 在Kotlin中,函数可以声明为具有类型的变量

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

    印刷品:

    [1023 = 3FF = 1111111111]

  • Kotlin允许操作员使用扩展和成员函数进行重载

    fun exampleOfOperatorOverloadingUsingExtensionFunction() {
        class MyType() {
            val strings: ArrayList<String> = ArrayList<String>()
            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}")
    }
    
    Run Code Online (Sandbox Code Playgroud)

    印刷品:

    {"one","two","three"}
    (myType.contains("four"))= false,(myType中为"three")= true

测试尝试
基于以上.我尝试invoke()使用类型(Boolean, Boolean, Boolean) -> Boolean作为扩展函数的接收器类型来创建函数的运算符重载的示例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)
    }
Run Code Online (Sandbox Code Playgroud)

印刷品:

func1 body
func2 body

预期:

重载的invoke运算符
重载的调用运算符

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

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

pdp*_*dpi 10

如在另一个答案中所述,invoke是在函数对象本身上定义的,因此您无法使用扩展方法覆盖它.

我认为这里更深层次的问题是对此功能的目的略有误解.让我们来看看plus对于+操盘手.

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

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

data class Complex(real: Double, img: Double)
Run Code Online (Sandbox Code Playgroud)

那么定义这个来计算复数是完全合理的:

operator fun Complex.plus(other: Complex): Complex {
  val real = this.real + other.real
  val img  = this.img + other.img
  return Complex(real, img)
}
Run Code Online (Sandbox Code Playgroud)

所以,用同样的事情invoke():的意思()是,这是任何类似于调用一个函数为你的类型,并重写invoke的东西,已经是一个功能是自找麻烦.您想要使用它的目的是为您自己的对象提供类似函数的语法.

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

interface MyCallback {
  fun call(ctx: MyContext)
}
Run Code Online (Sandbox Code Playgroud)

您使用通常的方式:

callback.call(ctx)
Run Code Online (Sandbox Code Playgroud)

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

operator fun MyCallback.invoke(ctx: Context) = this.call(ctx)

/* Elsewhere... */
callback(ctx)
Run Code Online (Sandbox Code Playgroud)

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