2015-03-31 75 views
2

假設我有以下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)來說似乎已經過時了,所以其他教程的指針也會很棒。

在實際例子中,大約有FooBar的實例,總共有100個組合,其中大約一半是無效的。而且,有效的組合可能在將來任意改變。

編輯

實際的問題是複雜一點。該Hello方法接受Seq如下:複雜的標準

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

實例是:

  1. 如果foos包含Foo1然後bars不能有Bar1
  2. foos一起不能包含Foo1Foo3

代碼示例:

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

除了@ DaunnC的回答,還有一個技術解釋[here](http://www.chuusai.com/2011/07/16/ fundeps合階/)。 – 2015-03-31 07:11:27

+0

是否有任何規則確定哪些組合是有效的,哪些不是? – 2015-03-31 17:45:16

+0

@MilesSabin號有效的組合是相當任意的..但有一定的規則..看到我上面的編輯。 – Jus12 2015-04-01 04:06:05

回答

3

沒有與類型的一招,不知道這是很漂亮(不漂亮的話),你必須手動編寫大量的這樣的規則,但MB您不需要使用大量的插件/庫:

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 
+3

這絕對是正確的選擇......在一流的Scala中有一個簡單的解決方案使用宏或插件是完全不合適的。 – 2015-03-31 07:09:32

+0

它也不那麼醜。似乎是最簡單的方法。 – Jus12 2015-03-31 07:44:01

+0

但是,我想使用插件。實際情況更復雜,因爲'Foo'和'Bar'本身是由其他類型組成的,'Hello'類將數組作爲參數。 – Jus12 2015-03-31 08:02:22