私はScalaでいくつかの演習を行ってきました。AnyVal
新しく追加されたトレイトを使用して、誤って互いに割り当てられない互換性のない値型を作成する方法を導出しようと考えました。
私が思いついた最高のものは次のようなものでした:
object Measurements {
trait ValueType[T] extends Any {
def value: T
}
trait Measurement[A <: ValueType[Double]] extends Any {
def modify(fn: (Double, A) => Double, value: A): A
def +(mod: A) = modify((x: Double, y: A) => x + y.value, mod)
def -(mod: A) = modify((x: Double, y: A) => x - y.value, mod)
def *(mod: A) = modify((x: Double, y: A) => x * y.value, mod)
def /(mod: A) = modify((x: Double, y: A) => x / y.value, mod)
}
case class Frequency(value: Double) extends AnyVal
with ValueType[Double]
with Measurement[Frequency]
{
def modify(fn: (Double, Frequency) => Double, mod: Frequency)
= Frequency(fn(value, mod))
}
case class Amplitude(value: Double) extends AnyVal
with ValueType[Double]
with Measurement[Amplitude]
{
def modify(fn: (Double, Amplitude) => Double, mod: Amplitude)
= Amplitude(fn(value, mod))
}
case class Wavelength(value: Double) extends AnyVal
with ValueType[Double]
with Measurement[Wavelength]
{
def modify(fn: (Double, Wavelength) => Double, mod: Wavelength)
= Wavelength(fn(value, mod))
}
}
import Measurements._
Frequency(150) + Frequency(10) // ==> Frequency(160)
Amplitude(23.2) * Amplitude(2) // ==> Amplitude(46.4)
Amplitude(50) + Frequency(50) // ==> Compile-time Type Error
残念ながら、ジェネリック型のmodify
ようなものを定義することは不可能であるため、インスタンスごとに関数を一意に定義する必要があります。コンストラクターの制約を定義する方法はないようです。それ以外の場合は、次のような特性に共通するものを定義できる場合があります。A(value)
A
def modify(fn: (Double, A) => Double, mod: A) = A(fn(value, mod))
を呼び出してみましapply(Double)
たA
が、ジェネリック変数からはアクセスできません。また、少なくとも物事を単純化するために、ある種のファクトリーを作り上げることができるかどうかを調べようとしましたが、現在行っていることよりも優雅なものを思いつくことができませんでした. 私はいつもC#で同じ問題に遭遇します。
異なる (しかし関連する) クラスの共通のコンストラクター型に依存するコードを除外する方法はありますか?