web-dev-qa-db-ja.com

Scalaのデフォルトのコンストラクターでコンストラクターの引数をチェックして例外をスローしたり、アサーションを作成したりするにはどうすればよいですか?

コンストラクターの引数を確認し、引数セットが有効でない場合(値が期待される制約に適合しない場合)にスローするIllegalArgumentExceptionの作成を拒否します。これをScalaでコーディングする方法は?

43
Ivan

Scalaでは、クラスの本体全体がプライマリコンストラクタであるため、検証ロジックをそこに追加できます。

scala> class Foo(val i: Int) {
     |   if(i < 0) 
     |     throw new IllegalArgumentException("the number must be non-negative.")
     | }
defined class Foo

scala> new Foo(3)
res106: Foo = Foo@3bfdb2

scala> new Foo(-3)
Java.lang.IllegalArgumentException: the number must be positive.

Scalaにはユーティリティメソッド require が用意されており、次のように同じことをより簡潔に記述できます。

class Foo(val i: Int) {
  require(i >= 0, "the number must be non-negative.")
}

より良いアプローチは、例外をスローする代わりにscalaz.Validation[String, Foo]を与えるファクトリメソッドを提供することかもしれません。 (注:Scalazが必要です)

scala> :paste
// Entering paste mode (ctrl-D to finish)

class Foo private(val i: Int)

object Foo {
  def apply(i: Int) = {
    if(i < 0)
      failure("number must be non-negative.")
    else
      success(new Foo(i))
  }
}

// Exiting paste mode, now interpreting.

defined class Foo
defined module Foo

scala> Foo(3)
res108: scalaz.Validation[Java.lang.String,Foo] = Success(Foo@114b3d5)

scala> Foo(-3)
res109: scalaz.Validation[Java.lang.String,Foo] = Failure(number must be non-negative.)
86
missingfaktor
scala> class Foo(arg: Int) {
     |   require (arg == 0)
     | }
defined class Foo

scala> new Foo(0)
res24: Foo = Foo@61ecb73c

scala> new Foo(1)
Java.lang.IllegalArgumentException: requirement failed
18
Luigi Plinge