考えられる解決策は 2 つあります。
最初にUnboxed Type Tagsを見てください。整数をボックス化することなく、コンパイル時に型をアタッチできます。コンパイラは必要に応じてそれらを使用するよう強制しますが、値は実行時にチェックされます。
引用された記事から、次のように書くことができます:
type Tagged[U] = { type Tag = U }
type @@[T, U] = T with Tagged[U]
trait Positive
trait One2Three
type PositiveInt = Int @@ Positive
type SmallInt = Int @@ One2Three
//Builds a small int
def small(i: Int): SmallInt = {
require( i > 0 && i < 4, "should be between 1 and 3" )
i.asInstanceOf[SmallInt]
}
//Builds a positive int
def positive( i: Int): PositiveInt = {
require( i >= 0, "should be positive" )
i.asInstanceOf[PositiveInt]
}
//Example usage in methods
def mul( i: SmallInt, j: PositiveInt ): PositiveInt = positive(i*j)
次にREPLで:
scala> mul( small(2), positive(4) )
res1: PositiveInt = 8
scala> mul( small(4), positive(2) ) //RUNTIME ERROR
java.lang.IllegalArgumentException: should be between 1 and 3
scala> mul( 2, positive(2) ) //COMPILE TIME ERROR
<console>:16: error: type mismatch;
found : Int(2)
required: SmallInt
mul( 2, positive(2) )
^
2 番目の解決策は、Scala 2.10 用に提案された値クラスです。SIP-15を読んで、それらの使用方法を確認できます。