2017-03-08 85 views
4

鑑於含有下列(冷凝)類的Java庫: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; 
    } 

    /* ... */ 
} 

由於自動地科特林合適方法名轉換成重載操作,我可以寫

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! 
+1

如果有興趣,請點擊這裏(https://github.com/elect86/glm)glm port – elect

+0

@選擇使用你的端口是最好的解決方案,爲什麼你不作爲回答發佈? – voddan

+0

害怕出現太多堅持/侵入性,但既然你建議,我會試試.. – elect

回答

1

理想情況下,你會改變的Java類,以使其操作功能遵守公約更好。如果您無法修改原始課程,那麼您在使用Kotlin時始終可以使用/運營商。

因爲它是原班裏面,你將無法與擴展功能來覆蓋它,原來總是優先於它,無論在哪裏擴展聲明,或者它如何進口。

你要麼必須習慣於可用的語法,要麼你真的不能擁有這些語法,你可以創建一個圍繞Vector2f的包裝類,它沒有公開提供該名稱的功能。

+0

這是一種悲傷,因爲圖書館是非常好的。但使用運營商超載,完全令人驚訝,你是壞的:( – baeda

+0

'@ kotlin.internal.HidesMembers'會解決問題,但你知道,如果你爲JetBrains工作.. – voddan

3

我的工作GLM端口here

。對於你的榜樣,相關代碼here

operator fun div(b: Float) = div(Vec2(), this, b, b) 
operator fun div(b: Vec2) = div(Vec2(), this, b.x, b.y) 

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, b.x, b.y) 

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, b.x, b.y) 

背後的邏輯很簡單,引用您的樣品,最短/最簡單的代碼:

val v0 = Vec2(12f) 
val v1 = Vec2(2f) 

val res = v0/v1 

總是創建一個新的實例。這不知何故遵循也編寫在Kotlin docs上的指導原則。以及目前仍然存在的inc()dec()部分(它在此期間被修改)。

而且是不易出錯的形式儘可能(個人經驗..)

對於性能的關鍵場景,當你不想分配一個新的實例,妥協是要放棄的操作符重載通過v1

v0.div(v1, res) 

這意味着,除v0和結果放在res:並使用函數形式。

如果您想接收對象變異,並直接容納結果:

v0 div_ v1 

這背後的想法是利用相似下劃線_和等號=後面解釋div_/=

+0

我upvoted的努力,我敢肯定因爲它沒有提供問題的答案('我可以讓kotlin接受我的運算符而不是自動生成的'),所以我不能接受你的GLM端口這是正確的,我很害怕! – baeda

+1

是啊,別擔心,我完全理解它,謝謝你的提升:)我希望它對那些會遇到類似問題的人有用 – elect