我的函数有1个参数,类型是字符串,但长度是4,我可以在编译时验证这个参数吗?
在haskell和F#中有类型级别,它可以在编译时验证,如nonEmptyList。
如何在scala中创建它。我认为不加思索可以做到这一点,但我不明白
感谢您提前建议
答案 0 :(得分:3)
是的,Shapeless可以做到这一点。也许是这样的:
def f(s: Sized[IndexedSeq[Char], Nat._4]): ...
但是,你无法直接将字符串传递给它。您必须执行f(Sized('a', 'b', 'c', 'd'))
答案 1 :(得分:0)
你不能用香草Scala。
您可以采用的最佳方法是为此创建一种特殊类型 -
case class SpecialString(string: String) {
require(string.length == 4)
}
然后,让您的函数接收SpecialString
作为参数,而不是String
。
答案 2 :(得分:0)
使用宏也是编译时验证的一个选项。请参阅Arnout Engelen撰写的这篇文章:http://blog.xebia.com/compile-time-evaluation-scala-macros/
我修改了他的例子来定义一个字符串验证函数:
object CompileTimeStringCheck {
import scala.language.experimental.macros
// This function exposed to consumers has a normal Scala type:
def stringCheck(s: String): String =
// but it is implemented as a macro:
macro CompileTimeStringCheck.stringCheck_impl
import scala.reflect.macros.blackbox.Context
// The macro implementation will receive a 'Context' and
// the AST's of the parameters passed to it:
def stringCheck_impl(c: Context)(s: c.Expr[String]): c.Expr[String] = {
import c.universe._
// We can pattern-match on the AST:
s match {
case Expr(Literal(Constant(nValue: String))) =>
// We perform the calculation:
val result = normalStringCheck(nValue)
// And produce an AST for the result of the computation:
c.Expr(Literal(Constant(result)))
case other =>
// Yes, this will be printed at compile time:
println("Yow!")
???
}
}
// The actual implementation is regular old-fashioned scala code:
private def normalStringCheck(s: String): String =
if (s.length == 4) return s
else throw new Exception("Baaaaaah!")
}
这里有一个问题:这需要在可以使用之前进行编译,即将其放入utils jar或其他东西。然后你可以在以后的编译时使用它:
import CompileTimeStringCheck._
object Test extends App {
println(stringCheck("yes!"))
}
再次,请参阅Arnout Engelen的帖子了解更多详情和原始解决方案(http://blog.xebia.com/compile-time-evaluation-scala-macros/)。