问题
Suppose I have the following Scala code:
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
I need to catch at compile time if any incompatible combination is applied to Hello
. Suppose only the following combinations are allowed: (Foo1, Bar1)
, (Foo1, Bar2)
, (Foo2, Bar3)
and (Foo3, Bar3)
.
Is it possible to test this during compile time? I realize that plugins and macros may allow me to do this. Some hints would be appreciated. The above tutorials seem outdated for the latest versions of Scala (2.11.x), so pointers to other tutorials would also be great.
In the real example, there are about 10 instances of Foo
and Bar
, giving a total of 100 combinations, about half of them invalid. Furthermore, the valid combinations could change arbitrarily in future.
EDIT
Actual problem is bit more complex. The Hello
method takes in Seq
as follows:
case class Hello(foos:Seq[Foo], bars:Seq[Bar])
Examples of complex criteria are:
- If
foos
containFoo1
thenbars
cannot haveBar1
. foos
cannot containFoo1
andFoo3
together.
Code examples:
Hello(Seq(Foo1), Seq(Bar2, Bar3)) // valid
Hello(Seq(Foo1, Foo3), Seq(Bar1)) // invalid due to rule 2
回答1:
There is a trick with types, not sure it is very beautiful (not beautiful at all), and you have to write lots of such rules manually, but mb you don't need to use heavy plugins / libs:
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
来源:https://stackoverflow.com/questions/29361147/add-custom-compile-time-checks-to-scala