Java方法错误地自动在kotlin中重载
给定一个包含以下(精简)类的Java库:
public class Vector2f { public float x; public float y; public Vector2f div(Vector2f other) { x /= other.x; y /= other.y; return this; } public Vector2f div(Vector2f other, Vector2f dest) { dest.x = x / other.x; dest.y = y / other.y; return dest; } /* ... */ }
由于kotlin自动将合适的方法名称转换为重载操作符,我可以写
val v0 = Vector2f(12f, 12f) val v1 = Vector2f(2f, 2f) val res = v0 / v1 println(v0) println(v1) println(res) res.x = 44f println() println(v0) println(v1) println(res)
…意外的结果是v0
被中缀除法操作所突变。 此外, res
存储的引用指向与v0
相同的对象。输出:
Vector2f(6.0, 6.0) Vector2f(2.0, 2.0) Vector2f(6.0, 6.0) Vector2f(44.0, 6.0) Vector2f(2.0, 2.0) Vector2f(44.0, 6.0)
由于库也提供了一个重载将结果写入另一个向量,我想知道是否可以告诉kotlin不要使用提供的Vector2f.div(Vector2f)
方法。
我已经试过向Vector2f
提供一个扩展方法,但是被真实成员所影响:
operator fun Vector2f.div(other: Vector2f): Vector2f = this.div(other, Vector2f()) ^~~ extension is shadowed by a member: public open operator fun div(other: Vector2f!): Vector2f!
理想情况下,您可以更改Java类,使其运算符功能更好地遵守惯例。 如果您无法修改原始类,那么在使用Kotlin时,您始终可以使用/
运算符。
由于它在原始类中,因此无法使用扩展函数覆盖它,原始文件总是优先于它,而不管扩展名是在哪里声明的或者是如何导入的。
你要么必须使用可用的语法,要么你真的不能拥有这个语法,你可以创建一个围绕Vector2f
的包装类,它没有公开提供这个名称的功能。
我在这里工作glm端口
对于你的例子,相关的代码在这里
operator fun div(b: Float) = div(Vec2(), this, b, b) operator fun div(b: Vec2) = div(Vec2(), this, bx, by) fun div(bX: Float, bY: Float, res: Vec2 = Vec2()) = div(res, this, bX, bY) fun div(b: Float, res: Vec2 = Vec2()) = div(res, this, b, b) fun div(b: Vec2, res: Vec2 = Vec2()) = div(res, this, bx, by) fun div_(bX: Float, bY: Float) = div(this, this, bX, bY) infix fun div_(b: Float) = div(this, this, b, b) infix fun div_(b: Vec2) = div(this, this, bx, by)
背后的逻辑很简单,引用你的示例,最短/最简单的代码:
val v0 = Vec2(12f) val v1 = Vec2(2f) val res = v0 / v1
总是创建一个新的实例。 这不知何故遵循也被写在Kotlin文档上的准则。 inc()
和dec()
部分仍然存在(同时它已被修改)。
也是尽可能不容易出错的形式(个人经验..)
对于性能严重的情况,当你不想分配一个新的实例时,妥协就是放弃操作符重载并使用函数形式:
v0.div(v1, res)
这意味着,将v0
除以v1
,并将结果res
。
如果你想让接收者对象变异并直接调用结果:
v0 div_ v1
这背后的想法是利用下划线_
和等号=
以及解释div_
as /=
后面的相似性