【Kotlin疑惑】在Kotlin类中重载一个算术运算符,并把该运算符声明为扩展函数会发生什么?

435 阅读3分钟

在Kotlin类中重载一个算术运算符,并把该运算符声明为扩展函数会发生什么?

实例

image.png

此时调用'+'运算符

image.png

报错如下

image.png

对错误进行解读 由于接收者类型无法匹配导致无法从候选方法中找到可以应用的

对错误进行分析

分析三种不同方式重载的plus函数

第一种:以标准的扩展函数形式重载plus函数

image.png

把kotlin代码反编译成java代码

image.png 通过反编译后我们可以发现此时plus函数处于PointKt类中,这也符合了我们之前篇章中说到“扩展函数并不是类的一部分,而是声明在类之外的”,在java中它把这个函数声明在了有着相似类名的类中,并且是一个静态函数。作为拓展函数的plus有着两个参数,kotlin在调用'+'时在java中被编译成下图

第二种:以标准的成员函数形式重载plus函数

image.png

把kotlin代码反编译成java代码

image.png
反编译后我们可以发现作为成员函数的plus现在只有一个参数,而kotlin在调用'+'时在java中被编译成下图

image.png

第三种:成员函数形式与扩展函数形式混合使用

image.png

把kotlin代码反编译成java代码

image.png

总分析

前两种形式是没有问题的写法,让我们着眼第三种的用法。把第三种的java代码与前两种的java代码相结合我们可以找出它们之间的一些联系与区别

联系与区别

它和第二种中的plus函数一样是Point类中的成员函数,但却有着两个参数 它和第一种中的plus函数一样有着两个参数,但没有第一种中plus函数的static声明

第三种编译出来的函数就像是缝合了前两种函数的写法一般。前面我们给出了第一种和第二种在调用plus函数的样子,而我们也可以据此推断出第三种调用时的样子:point.plus(?,new Point(3,4))。此时我就在想既然错误提示我们接收者类型不能匹配上,那为什么编译器不能把本身作为参数传入函数中呢?我可以尝试自己写一个带有两个参数的并且是运算符重载的plus函数吗?

结果如下

image.png 在kotlin层面重载该算术运算符只能存在一个参数

我猜想在kotlin编译器中在调用算术运算符时,若是成员函数只会提供一个参数的写法,若是扩展函数则使用提供两个参数的写法。第三种写法的plus函数既是成员函数又需要两个参数,可能就是如此才导致第三种写法无法成功运行

从equals方法我们可以看出继承自Any类的实现始终优先于扩展函数,而我们这种情况虽然不是继承自Any类,但是否也有着优先级的区别呢?

以上仅为我自己的想法,若有不同见解可以讨论,若有错误也请指出