infix
組み込み型 (Double など) にメソッドを追加して、演算子を使用できるようにしたいと考えています。それは可能ですか?
2 に答える
はいといいえ。はい、 にメソッドを追加したようにdouble
見せることができます。例えば:
class MyRichDouble(d: Double) {
def <>(other: Double) = d != other
}
implicit def doubleToSyntax(d: Double) = new MyRichDouble(d)
<>
このコードは、以前は使用できなかった演算子を type の任意のオブジェクトに追加しますDouble
。doubleToSyntax
メソッドがスコープ内にあり、修飾なしで呼び出すことができる限り、次のことが機能します。
3.1415 <> 2.68 // => true
Double
答えの「いいえ」の部分は、実際にはクラスに何も追加していないという事実から来ています。代わりに、必要なメソッドを定義する新しい型への変換を作成しDouble
ています。これは、多くの動的言語が提供するオープン クラスよりもはるかに強力な手法です。また、たまたま完全に型安全です。:-)
注意すべきいくつかの制限事項:
- この手法では、既存のメソッドを削除または再定義することはできません。新しいメソッドを追加するだけです
- 目的の拡張メソッドを使用できるようにするには、暗黙的な変換メソッド (この場合は
doubleToSyntax
) がスコープ内にある必要があります。
慣用的には、暗黙的な変換は、シングルトン オブジェクト内に配置されてインポートされるか (例: import Predef._
)、またはトレイト内に配置されて継承されます (例: class MyStuff extends PredefTrait
)。
余談ですが、Scala の「中置演算子」は実際にはメソッドです。<>
メソッドを中置できるようにする魔法はありません。パーサーは単にその方法でそれを受け入れます。必要に応じて、「通常のメソッド」を中置演算子として使用することもできます。たとえば、Stream
クラスはtake
、単一のInt
パラメーターを取り、 new を返すメソッドを定義しますStream
。これは次のように使用できます。
val str: Stream[Int] = ...
val subStream = str take 5
str take 5
式は文字どおり と同じstr.take(5)
です。
この機能は、エラー推定を実行するクラスを実装するのに役立ちました。
object errorEstimation {
class Estimate(val x: Double, val e: Double) {
def + (that: Estimate) =
new Estimate(this.x + that.x, this.e + that.e)
def - (that: Estimate) =
new Estimate(this.x - that.x, this.e + that.e)
def * (that: Estimate) =
new Estimate(this.x * that.x,
this.x.abs*that.e+that.x.abs*this.e+this.e*that.e)
def / (that: Estimate) =
new Estimate(this.x/that.x,
(this.x.abs*that.e+that.x.abs*this.e)/(that.x.abs*(that.x.abs-that.e)))
def +- (e2: Double) =
new Estimate(x,e+e2)
override def toString =
x + " +- " + e
}
implicit def double2estimate(x: Double): Estimate = new Estimate(x,0)
implicit def int2estimate(x: Int): Estimate = new Estimate(x,0)
def main(args: Array[String]) = {
println(((x: Estimate) => x+2*x+3*x*x)(1 +- 0.1))
// 6.0 +- 0.93
println(((x: Estimate) => (((y: Estimate) => y*y + 2)(x+x)))(1 +- 0.1))
// 6.0 +- 0.84
def poly(x: Estimate) = x+2*x+3/(x*x)
println(poly(3.0 +- 0.1))
// 9.33333 +- 0.3242352
println(poly(30271.3 +- 0.0001))
// 90813.9 +- 0.0003
println(((x: Estimate) => poly(x*x))(3 +- 1.0))
// 27.037 +- 20.931
}
}