私は@specialized
クラスと値クラスがどのように機能するかを知っており、次のような特殊な値クラスを持つことはできないことを知っています:
class MilliVolt[@specialized T](val content :T) extends AnyVal //illegal
同様の効果を得る方法が見つかりません。単一の宣言で、複数の Java プリミティブに対する純粋な構文ラッパーとして機能するユーザー型/型コンストラクターを作成します。この制限を回避する方法はありますか?
値クラスの背後にある主な動機の 1 つは、ビジネス上の意味を持つ値型に「注釈を付け」、そのデータの型とは異なる型を作成することでした。
class MilliVolts(val count :Long) extends AnyVal
ボックス化されたタイプを静的に知っている限り、これは非常にうまく機能しますが、いくつかの異なるプリミティブをミリボルトとして扱いたい場合は、プリミティブごとに新しいラッパーを作成するか、それらが設計されたものにジェネリックを使用するオプションがありますに:
trait Scale
trait millivolts extends Scale
trait milliampere extends Scale
class of[N, U<:Scale](val amount :N) extends AnyVal
val voltage :Long of millivolts = new of(1L)
val current :Int of milliampere = new of(1)
これはすべて甘いもので、実際にof
ラッパーはコンパイル時に削除されますが、残念ながらプリミティブは Java ラッパーにボックス化され、2 つのフィールドは次のようにコンパイルされます。
Integer voltage = scala.Long.box(1L)
Integer current = scala.Int.box(1)
long
およびint
フィールドではありません。
次のようなコードを書くことは可能ですか?
- 単一の宣言(新しい「ユニット」タイプ)で新しいそのようなラッパーを作成できます。
- 少なくとも基礎となるプリミティブ (ミリボルトで動作するメソッド、ボックス化されたプリミティブからの抽象化) に関して、そのようなラッパーで一般的な操作を実行します。
- ラッパー型と基になるプリミティブ型の両方が完全にインスタンス化され (ジェネリック型の型パラメーターではない)、呼び出されたメソッドをインライン化できる場合は、ボクシングを実行しません (したがって、現在および将来のすべてのユニットに対して追加を 1 回定義できます)。
- 理想的には、クライアント コードのマクロに依存しません (型宣言自体が IDE で理解できる限り、実装での使用は問題ありません)。