将Scala运算符添加到最终的Java类

Ole*_*Ole 3 java scala final overloading operator-keyword

我在Scala中使用了jMonkeyEngine(Java游戏引擎),到目前为止效果非常好,但现在我问自己是否有一种优雅的方法可以为Vector3f(和类似的)类重载运算符.我的第一个想法是继承并重Vector3f载运算符,但这Vector3f是最终的,所以这不是一个选项.接下来我想也许我可以使用静态方法运行的单例/ scala对象Vector3f,如下所示,但这也不起作用:

object VectorMath {
    def *(factor: Float, vector: Vector3f) = vector.mult(factor)
}

//and then somewhere
import VectorMath._
var v = new Vector3f(1,2,3);
var u = 1.2f * v; //this does not work, because Float does not have * overloaded for Vector3f
var u = VectorMath.*(1.2f, v); //this does work, but defeats the purpose
Run Code Online (Sandbox Code Playgroud)

所以我现在想到的是将Vector3f包装在一个新的Scala类中,并将操作符调用委托给适当的Java方法.然而,这有三个缺点:

  1. 我将不得不做很多来回转换(a toVector3ffromVector3f方法或类似的东西).
  2. 当我有Vector3f/ScalaVectors数组时,这个问题变得更糟.由于类不相关(除了组合),每次我在jME中调用方法时,我都必须手动转换数组的每个元素.
  3. 即便如此,我知道没有办法为我的新ScalaVector类重载一个操作符,以便我可以在前面使用该因子,即1.2f * v.

我的问题:有人可以想办法让这更自然/更优雅吗?你如何解决类似的问题?或者是否有一些我不知道的Scala语法来做这些事情?在C++中,我将创建一个全局运算符,它将float和Vector3f作为参数并且可能是它的朋友.什么是Scala方式来做到这一点,还是那根本不可能?

kir*_*uku 12

或者是否有一些我不知道的Scala语法来做这些事情?

是的,有一些暗示:

class VectorMath(f: Float) { def * (v: Vector3f) = v mult f }
implicit def VectorMath(f: Float) = new VectorMath(f)

val v = new Vector3f(1,2,3)
1.2F * v
// treated as: VectorMath(1.2F).*(v)
Run Code Online (Sandbox Code Playgroud)

从Scala 2.10开始,隐式转换也可以写成:

implicit class VectorMath(f: Float) { def * (v: Vector3f) = v mult f }
Run Code Online (Sandbox Code Playgroud)

从2.10开始,还有一些值类,这些值由编译器优化以获得更好的性能:

implicit class VectorMath(val f: Float) extends AnyVal { def * (v: Vector3f) = v mult f }
Run Code Online (Sandbox Code Playgroud)

  • 哦,哇,我恋爱了 - 这真是太棒了.谢谢! (2认同)