将自定义编译时检查添加到Scala

时间:2015-03-31 05:24:33

标签: scala scala-2.10 scala-2.11

假设我有以下Scala代码:

sealed trait Foo
sealed trait Bar
object Foo1 extends Foo
object Foo2 extends Foo
object Foo3 extends Foo
object Bar1 extends Bar
object Bar2 extends Bar
object Bar3 extends Bar
case class Hello(foo:Foo, bar:Bar)

val a = Hello(Foo1, Bar2) // allowed
val b = Hello(Foo2, Bar2) // suppose not allowed 

如果对Hello应用了任何不兼容的组合,我需要在编译时捕获。假设仅允许以下组合:(Foo1, Bar1)(Foo1, Bar2)(Foo2, Bar3)(Foo3, Bar3)

是否可以在编译期间对此进行测试? 我意识到pluginsmacros可能允许我这样做。一些提示将不胜感激。上面的教程似乎已经过时了Scala(2.11.x)的最新版本,所以指向其他教程的指针也会很棒。

在实际示例中,大约有10个FooBar个实例,总共有100个组合,其中大约一半无效。此外,有效组合将来可能会随意改变。

修改

实际问题有点复杂。 Hello方法接受Seq,如下所示:

case class Hello(foos:Seq[Foo], bars:Seq[Bar]) 

复杂标准的例子有:

  1. 如果foos包含Foo1,则bars不能包含Bar1
  2. foos不能同时包含Foo1Foo3
  3. 代码示例:

    Hello(Seq(Foo1), Seq(Bar2, Bar3)) // valid 
    Hello(Seq(Foo1, Foo3), Seq(Bar1)) // invalid due to rule 2
    

1 个答案:

答案 0 :(得分:3)

有一种类型的技巧,不确定它是非常漂亮的(根本不漂亮),你必须手动编写很多这样的规则,但是你不需要使用繁重的插件/库:

trait Validator[F, S] { }
object Validator {
    implicit object firstPair extends Validator[Foo1.type, Bar1.type]
    implicit object secondPair extends Validator[Foo1.type, Bar2.type]
    implicit object thirdPair extends Validator[Foo2.type, Bar3.type]
    implicit object fourthPair extends Validator[Foo3.type, Bar3.type]
}

case class Hello[F <: Foo, S <: Bar](foo: F, bar: S)(implicit v: Validator[F, S])

val a = Hello(Foo1, Bar2) // allowed
val b = Hello(Foo2, Bar2) // break in compile time
相关问题