Kotlin – 函数的调用操作符重载
我正在学习Kotlin – 运算符重载
我想了解(例如)运算符重载如何为函数的invoke()
函数工作
预先测试
-
Kotlin的扩展函数
fun exampleOfExtensionFunction() { fun Int.randomize(): Int { return Random(this.toLong()).nextInt() } val randomizedFive = 5.randomize() println("$randomizedFive") }
打印:
-1157408321
-
在Kotlin中,函数可以用类型声明为变量
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<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}") }
打印:
{ “一二三” }
(myType.contains(“four”))= false,(myType中的“three”)= true
测试尝试
基于以上。 我试图用扩展函数invoke(flag1: Boolean, flag2: Boolean, flag3: Boolean)
的类型(Boolean, Boolean, Boolean) -> Boolean
作为接收器类型来创建函数invoke()
运算符重载的示例。 然而,这并没有如预期的那样工作。
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是在函数对象本身上定义的,所以你不能用扩展方法来覆盖它。
我认为这里的更深层次的问题是对这个功能目的的轻微误解。 我们来看看+
运算符的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
和()
相同的事情()
的含义是,无论类似于为你的类型调用一个函数,重写invoke
已经是函数的东西,只是要求麻烦。 你想用它来代替是为你自己的对象提供函数式的语法。
例如,假设你像这样定义一个接口:
interface MyCallback { fun call(ctx: MyContext) }
你用哪种方式:
callback.call(ctx)
但是通过invoke
运算符重载的实现,您可以将其用作函数:
fun MyCallback.invoke(ctx: Context) = this.call(ctx) /* Elsewhere... */ callback(ctx)
希望澄清你如何使用invoke
/ ()
您的问题必须以解决方案优先。 根据Kotlin文档 :
如果一个类有一个成员函数,并且定义了一个具有相同接收器类型,相同名称并适用于给定参数的扩展函数,则该成员总是获胜 。
因此,您的operator fun ((Boolean, Boolean, Boolean) -> Boolean).invoke(...)
扩展函数永远不会被调用,因为成员invoke
优先。
另一个答案
这确实是运营商超载,但通过扩展。 同样,因为(Boolean, Boolean, Boolean) -> Boolean
已经有一个fun invoke(Boolean, Boolean, Boolean): Boolean
定义,您的扩展失去。