次のように、クラスにいくつかの演算子を定義するとします。
class A {
def +(f: Float) = /* ... */
}
val a: A = new A
これによりa + 1f
、十分に簡単に行うことができます。ライブラリのユーザーも書き込みできるようにしたい場合はどうすればよい1f + a
ですか? どうすればそれを実装できますか?
次のように、クラスにいくつかの演算子を定義するとします。
class A {
def +(f: Float) = /* ... */
}
val a: A = new A
これによりa + 1f
、十分に簡単に行うことができます。ライブラリのユーザーも書き込みできるようにしたい場合はどうすればよい1f + a
ですか? どうすればそれを実装できますか?
Scala 2.9 では、この暗黙的な変換をインポートできます。
implicit def floatPlusAExtender (x: Float) =
new {
def + (a: A) = a + x
}
そして好きなように使ってください。Scala 2.10 以降では、この変換を次のように行う方がよいでしょう。
implicit class FloatPlusAExtender (x: Float) {
def + (a: A) = a + x
}
または次のようにさらに良い:
implicit class FloatPlusAExtender (val x: Float) extends AnyVal {
def + (a: A) = a + x
}
最後の方法はValue Classと呼ばれ、前の 2 つの方法とは異なり、この機能をオーバーヘッドなしで提供します。(ありがとう、axel22) これも 2.10 に付属する新しいものです。
A
または、次のように変更することもできます。
class A {
def + (x: Float) = /* ... */
def +: (x: Float) = this + x
}
次のように使用します。
1f +: a
最後のアプローチが望ましいです。
1 つのアプローチはpimp-my-library-patternです。
class FloatWithPlusA(f: Float) {
def +(a: A) = a + f
}
implicit def floatPlusA(f: Float): FloatWithPlusA =
new FloatWithPlusA(f)
val a: A = new A
a + 1.0f /* a.+(1.0f) */
1.0f + a /* floatPlusA(1.0f).+(a) */
もう 1 つのアプローチは、右結合メソッドを追加することですが、2 つの演算子の構文が異なるという明らかな欠点があります。
class A {
val f: Float = 1.0f
def +(f: Float) = this.f + f
def +:(f: Float) = this.f + f
}
val a: A = new A
a + 1.0f
1.0f +: a