问题描述
假设我有以下Scala代码:
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
如果将任何不兼容的组合应用于Hello
,则需要在编译时捕获.假设仅允许以下组合:(Foo1, Bar1)
,(Foo1, Bar2)
,(Foo2, Bar3)
和(Foo3, Bar3)
.
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)
.
是否可以在编译期间对此进行测试?我意识到插件和宏可能允许我这样做.一些提示将不胜感激.上述教程对于最新版本的Scala(2.11.x)似乎已经过时,因此指向其他教程的指针也将非常有用.
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.
在实际示例中,大约有10个Foo
和Bar
实例,总共提供了100种组合,其中大约有一半是无效的.此外,有效的组合将来可能会任意更改.
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.
编辑
实际问题更加复杂. Hello
方法采用Seq
如下:
Actual problem is bit more complex. The Hello
method takes in Seq
as follows:
case class Hello(foos:Seq[Foo], bars:Seq[Bar])
复杂标准的示例是:
- 如果
foos
包含Foo1
,则bars
不能具有Bar1
. -
foos
不能同时包含Foo1
和Foo3
.
- If
foos
containFoo1
thenbars
cannot haveBar1
. foos
cannot containFoo1
andFoo3
together.
代码示例:
Hello(Seq(Foo1), Seq(Bar2, Bar3)) // valid
Hello(Seq(Foo1, Foo3), Seq(Bar1)) // invalid due to rule 2
推荐答案
类型有一个窍门,不确定它是否非常漂亮(一点也不漂亮),您必须手动编写很多这样的规则,但是mb您不需要使用繁重的插件/库:
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
这篇关于将自定义编译时间检查添加到Scala的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!