我有这个简单的代码
def doStuff(x: Int) = {
...
}
但是,如果x小于或等于0,则此方法不支持,因此我使用require
def doStuff(x: Int) = {
require(x > 0, "x should be greater than 0")
}
doStuff(0) // runtime exception
但这发生在运行时异常中,如何更改它以使用Implicit在编译时显示错误?
非常感谢提前
答案 0 :(得分:10)
在一般情况下,这绝对不可能 - 编译器没有足够的关于任意Int
的信息。不过,你确实有几个选择。如果您愿意将参数作为文字,则可以使用宏:
import scala.language.experimental.macros, scala.reflect.macros.Context
def doStuffImpl(c: Context)(x: c.Expr[Int]): c.Expr[Unit] = {
import c.universe._
x.tree match {
case Literal(Constant(xLit: Int)) if xLit > 0 => c.literalUnit
case Literal(Constant(xLit: Int)) =>
c.abort(c.enclosingPosition, "x must be > 0")
case _ => c.abort(c.enclosingPosition, "x must be a literal")
}
}
def doStuff(x: Int) = macro doStuffImpl
然后:
scala> doStuff(1)
scala> doStuff(0)
<console>:12: error: x must be > 0
doStuff(0)
^
scala> val y = 1
y: Int = 1
scala> doStuff(y)
<console>:13: error: x must be a literal
doStuff(y)
^
也可以使用类似Shapeless的类型级自然数字:
import shapeless._, nat._, ops.nat.{ Diff, LT }
def doStuff(n: Nat)(implicit lt: LT[_0, n.N]) = ()
现在你可以做更复杂的事情:
def doStuffWithDiff[C <: Nat](a: Nat, b: Nat)(implicit
sum: Diff.Aux[a.N, b.N, C],
lt: LT[_0, C]
) = doStuff(Witness.witnessN[C].value)
现在doStuffWithDiff(10, 10)
和doStuffWithDiff(10, 11)
无法编译,但doStuffWithDiff(10, 9)
将会编译。
这是一种dependently typed programming,它可以非常强大,但是尝试在Scala中执行它(如果你真的很眯眼,它只是一种依赖类型的编程语言)会引入相当多的数量语法开销,所以你可能只想在编译时正确性非常高的情况下使用这种方法。
答案 1 :(得分:0)
最常见的替代方法是定义一个简单的包装类PositiveInt(或任何最适合的名称),它使运行时检查。您的功能将始终具有预期的功能......