将自定义编译时间检查添加到Scala [英] Add custom compile time checks to Scala

查看:101
本文介绍了将自定义编译时间检查添加到Scala的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有以下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).

是否可以在编译期间对此进行测试? 我意识到插件

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个FooBar实例,总共提供了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]) 

复杂标准的示例是:

  1. 如果foos包含Foo1,则bars不能具有Bar1.
  2. foos不能同时包含Foo1Foo3.
  1. If foos contain Foo1 then bars cannot have Bar1.
  2. foos cannot contain Foo1 and Foo3 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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆