Scala:我们可以在密封的案例类声明中预先将保护条件与模式匹配结合起来

时间:2012-08-11 12:05:44

标签: scala

是否可以将保护条件与密封案例类声明中的模式匹配相结合?

我意识到可以在匹配区块中包含保护条件,但我觉得在密封的案例类中预先定义这些条件是有益的。 这将允许开发人员定义严格的可能输入集,编译器在模式匹配时将检查这些输入。

总而言之,我希望能够做到这样的事情:

// create a set of pattern matchable cases with guards built in

sealed abstract class Args
case class ValidArgs1(arg1:Int,arg2:Int) if arg1>1 && arg2<10 extends Args
case class ValidArgs2(arg1:Int,arg2:Int) if arg1>5 && arg2<6 extends Args
case class InvalidArgs(arg1:Int,arg2:Int) if arg1<=1 && arg2>=10 extends Args


// the aim of this is to achieve pattern matching against an exhaustive set of 
// pre-defined possibilities

def process(args:Args){
    args match 
    {
        case ValidArgs1 = > // do this
        case ValidArgs2= > // do this
        case InvalidArgs = > // do this
    }
}

2 个答案:

答案 0 :(得分:6)

+1是一个有趣的推测性问题。由于您不是在类型级别操作,因此无法在编译时验证实例化,除非可能对宏进行非常特殊的检查,例如当你将文字传递给构造函数时。

另一方面,模式匹配的场景是运行时操作。为了实现这一点,您可以使用提取器而不是案例类。

case class Args(arg1: Int, arg2: Int)
object ValidArgs1 {
  def apply(arg1: Int, arg2: Int): Args = {
    val res = Args(arg1, arg2)
    require(unapply(res))
    res
  }
  def unapply(args: Args): Boolean = args.arg1 > 1 && args.arg2 < 10
}

def process(args: Args) = args match {
  case ValidArgs1() => "ok"
  case _            => "invalid"
}

process(ValidArgs1(2, 9))
process(Args(1, 10))
process(Args(3, 4))

答案 1 :(得分:-1)

我不相信您将能够在Scala中编译时检查一般约束/断言,因为Scala没有执行此操作所需的static verifier。如果您有兴趣,请查看(研究)语言/工具,例如ESC/JavaSpec#DafnyVeriFast

使用type-level programmingScala macros可能有一些方法可以使用常规编译器Scala进行非常有限的静态检查,但这只是我的猜测,因为我不熟悉与他们中的任何一个。说实话,我必须承认,如果宏实际上可以帮助我,我会感到非常惊讶。

运行时断言检查有效,例如

case class Foo(arg1: Int, arg2: Int) {
  require(arg1 < arg2, "The first argument must be strictly less than " +
                       "the second argument.")
}

Foo(0, 0)
  /* java.lang.IllegalArgumentException: requirement failed:
   *     The first argument must be strictly less than the second
   *     argument.
   */

但这可能不是你想到的。