ポイント(1)については、Option
確かに十分なはずです。これは、scala は null 値をサポートしていますが、主に Java との互換性のためにサポートしているためです。Scala コードには null 値を含めるべきではなく、それを含む場所は非常にローカライズされた場所に制限し、できるだけ早くオプションに変換する必要があります (優れた scala コードでは null 値が伝播されることはありません)。そのため、慣用的な scala では、フィールドまたはパラメーターが型でないOption
場合、これは実際にはそれが必須であることを意味します。
現在、(実験的であり、私が知る限り完全にはサポートされていません) というNotNull
特性もあります。NotNullトレイトは 2.8 でどのように機能し、実際に使用している人はいますか?を参照してください。
ポイント (2) については、scala 2.10 ではvalue classesが導入されています。Int
それらを使用すると、実行時のオーバーヘッドなしでラップする独自のクラスを定義し、適切と思われる演算子を実装できます。実行時チェックを行う唯一の場所は、法線Int
から独自のものに変換するときNonNegativeInt
です (int が負の場合は例外をスローします)。このチェックは、新しい を作成するたびに実行されることに注意してください。つまりNonNegativeInt
、操作を実行するたびに実行されるため、null 以外のランタイムへの影響があります。しかし、Pascal はまったく同じ状況 (範囲チェックは Pascal で実行時に実行される) にあったので、これで問題ないと思います。
UPDATENonNegativeInt
: (ここでは名前を に変更UInt
)の実装例を次に示します。
object UInt {
def apply( i: Int ): UInt = {
require( i >= 0 )
new UInt( i )
}
}
class UInt private ( val i: Int ) extends AnyVal {
override def toString = i.toString
def +( other: UInt ) = UInt( i + other.i)
def -( other: UInt ) = UInt( i - other.i)
def *( other: UInt ) = UInt( i * other.i)
def /( other: UInt ) = UInt( i / other.i)
def <( other: UInt ) = i < other.i
// ... and so on
}
REPL での使用例:
scala> UInt(123)
res40: UInt = 123
scala> UInt(123) * UInt(2)
res41: UInt = 246
scala> UInt(5) - UInt(8)
java.lang.IllegalArgumentException: requirement failed
at scala.Predef$.require(Predef.scala:221)
at UInt$.apply(<console>:15)
...