3

Vector3f私はScalaでjMonkeyEngine(Java Game Engine)を使用していますが、これはこれまでのところかなりうまく機能していますが、 (および同様の)クラスの演算子をオーバーロードするエレガントな方法があるかどうかを自問しています。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

したがって、今考えられるのは、Vector3fを新しいScalaクラスでラップし、オペレーター呼び出しを適切なJavaメソッドに委任することだけです。ただし、これには3つの欠点があります。

  1. 私は多くの前後の変換(atoVector3ffromVector3fメソッドまたはそのようなもの)を行う必要があります。
  2. Vector3f / ScalaVectorsの配列がある場合、この問題はさらに悪化します。クラスは(構成を除いて)関連していないため、jMEでメソッドを呼び出すたびに、配列のすべての要素を手動でキャストする必要があります。
  3. それでも、新しいScalaVectorクラスの演算子をオーバーロードして、前に因子を含めることができるような方法はありません1.2f * v

私の質問:誰かがこれをより自然でエレガントにする方法を考えることができますか?同様の問題にどのように取り組みますか?それとも、このようなことをするために私が知らないScala構文があるのでしょうか?C ++では、floatとVector3fを引数として取り、場合によってはそれをフレンドにするグローバル演算子を作成します。これを行うためのScalaの方法は何ですか、それとも単に不可能ですか?

4

4 に答える 4

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)

Scala 2.10以降、暗黙の変換は次のように書くこともできます。

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

2.10以降、パフォーマンスを向上させるためにコンパイラーによって最適化される値クラスもあります。

implicit class VectorMath(val f: Float) extends AnyVal { def * (v: Vector3f) = v mult f }
于 2012-06-12T20:44:30.027 に答える
3

上記の暗黙のクラスについて述べたことに加えて、Scala 2.10以降、値クラスを使用して中間オブジェクトの作成を回避できるようになります。

基本的に、VectorMath上記を拡張する必要がありますAnyValVectorMathオブジェクトをメソッドの戻り値として使用せず、代わりにVectorMath操作を呼び出すだけの場合、実行時にオブジェクトはVectorMath割り当てられません。

于 2012-06-12T21:01:17.427 に答える
1

:これにより、コードが非常に読みにくくなる可能性があります。

暗黙の変換を使用して、ある種のラッパークラスを作成することができますVector3f(JavaコレクションなどのいくつかのJavaクラスを備えたScala標準ライブラリ自体はここを参照してください)

// Somewhere, for example in a package object
implicit def wrapVector3f (v: Vector3f) = new Vector3fWrapper ( v );

class Vector3fWrapper (v: Vector3f) {
    // Use the Vector3f object internally here
    // You can now delegate all methods to the underlying Vector3f object
    // For example:
    def * (v: Vector3f) = {
        // ...
    }

    // or:
    def * (f: Float) = {
        // ...
    }
}
于 2012-06-12T20:45:05.203 に答える
-1

左側のFloatに暗黙的に演算を追加できることは誰もがすでに指摘していますが、末尾にコロンを付けることで右結合演算子を作成できることを指摘したいと思います。

class Vector3f(…) {
  …
  def *:(f: Float) = …
}

var v = new Vector3f(1,2,3);
var u = 1.2f *: v; //this works without any implicit magic or boxing overhead

構文上のわずかなペナルティが必要ですが、別のオプションです。

于 2012-06-13T03:27:26.607 に答える