我目前正在研究Kotlin - Operator Overloading
我试图理解(通过一个例子)运算符重载如何为函数invoke()
函数
预测试
fun exampleOfExtensionFunction() {
fun Int.randomize(): Int {
return Random(this.toLong()).nextInt()
}
val randomizedFive = 5.randomize()
println("$randomizedFive")
}
打印:
-1157408321
In Kotlin, functions can be declared as variables with types
fun exampleOfFunctionType() {
val printNumber: (number: Int) -> Unit
printNumber = { number ->
println("[$number = ${number.toString(16).toUpperCase()} = ${number.toString(2)}]")
}
printNumber(1023)
}
打印:
[1023 = 3FF = 1111111111]
Kotlin allows operator overloading with both extension and member functions
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}")
}
打印:
{&#34; one&#34; ,&#34;两个&#34; ,&#34;三&#34; }
(myType.contains(&#34; four&#34;))= false,(&#34; my&#34; in myType)= 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)
}
打印:
func1 body
func2 body
预期:
重载调用操作符
重载的调用操作符
另一个问题:
究竟是什么? (如果它不是运算符重载)
operator fun ((Boolean, Boolean, Boolean) -> Boolean).invoke(flag1: Boolean, flag2: Boolean, flag3: Boolean): Boolean {
println("Overloaded invoke operator")
return flag1 && flag2 && flag3
}
答案 0 :(得分:10)
如另一个答案所述,invoke是在函数对象本身上定义的,因此你不能用扩展方法覆盖它。
我认为这里更深层次的问题是对此功能的目的略有误解。我们来看看plus
运营商的+
。
我认为您同意尝试定义operator fun Int.plus(b: Int): Int { /* ... */}
毫无意义,因为覆盖默认的+
运算符是非常危险的,是吗?
但是,如果您定义一个复数类:
data class Complex(real: Double, img: Double)
然后将这个定义为对复数进行求和是完全合理的:
operator fun Complex.plus(other: Complex): Complex {
val real = this.real + other.real
val img = this.img + other.img
return Complex(real, img)
}
因此,与invoke
和()
相同:()
的含义是,它类似于为您的类型调用函数,并覆盖invoke
on已经是功能的东西只是在寻找麻烦。您想要使用它的目的是为您自己的对象提供类似函数的语法。
例如,假设您定义了如下界面:
interface MyCallback {
fun call(ctx: MyContext)
}
你使用通常的方法:
callback.call(ctx)
但是通过实现invoke
运算符重载,您可以将其用作函数:
operator fun MyCallback.invoke(ctx: Context) = this.call(ctx)
/* Elsewhere... */
callback(ctx)
希望澄清您如何使用invoke
/ ()
答案 1 :(得分:4)
您的问题必须以分辨率优先。 According to the Kotlin docs:
如果一个类有一个成员函数,并且定义了一个具有相同接收器类型,相同名称且适用于给定参数的扩展函数,则成员总是胜出。
因此,永远不会调用operator fun ((Boolean, Boolean, Boolean) -> Boolean).invoke(...)
扩展函数,因为成员invoke
优先。
另一个答案
确实是运营商重载,但通过扩展。同样,由于(Boolean, Boolean, Boolean) -> Boolean
已经定义了fun invoke(Boolean, Boolean, Boolean): Boolean
,因此您的扩展程序会丢失。