我希望将变量限制为布尔整数表示(0或1),作为定义的输入。这可以通过我到目前为止看到的两种方式实现,一种在运行时实现,一种在编译时仅用于文本。
是否有可能以某种方式将两者结合起来,因此我可以创建一个在编译时拒绝超出范围的文字值的类型,但是还允许在运行时检查非文字输入?
/////////////////////////////
//Runtime guard for boolean
/////////////////////////////
object zero_or_one {
import scala.language.implicitConversions
class ZeroOrOneRuntime private (val value: Int) extends AnyVal
object ZeroOrOneRuntime {
def apply(v: Int) = {
require(v == 0 || v == 1, "0 or 1 accepted only")
new ZeroOrOneRuntime(v)
}
implicit def toZeroOrOneRuntime(v: Int) = ZeroOrOneRuntime(v)
}
implicit def toInt(nn: ZeroOrOneRuntime) = nn.value
}
import zero_or_one._
var a : ZeroOrOneRuntime = 0
val a_bad :ZeroOrOneRuntime = 2 //java.lang.IllegalArgumentException: requirement failed: 0 or 1 accepted only
for (i <- 0 to 10)
a = i //java.lang.IllegalArgumentException: requirement failed: 0 or 1 accepted only
使用scala精炼库https://github.com/fthomas/refined
//////////////////////////////////
//Compile-time guard for boolean
//////////////////////////////////
import eu.timepit.refined._
import eu.timepit.refined.api.Refined
import eu.timepit.refined.auto._
import eu.timepit.refined.numeric._
type ZeroOrOneLiteral = Int Refined Interval.Closed[W.`0`.T, W.`1`.T]
var b : ZeroOrOneLiteral = 1
val b_bad : ZeroOrOneLiteral = 2 //Right predicate of (!(2 < 0) && !(2 > 1)) failed: Predicate (2 > 1) did not fail.
for (i <- 0 to 10)
b = i //error: compile-time refinement only works with literals
与scala的创建者交换电子邮件后,这可能会在图书馆本身得到解决。我在GitHub here上打开了一个功能请求问题。如果库将使用此功能进行更新,我将更新此问题。
答案 0 :(得分:1)
您可以使用Refined.unsafeApply
跳过编译时检查。如果您想检查不安全的呼叫是否是运行时间,则必须手动执行。例如,使用隐式类:
type ZeroOrOneLiteral = Int Refined Interval.Closed[W.`0`.T, W.`1`.T]
implicit class castableZeroOrOneLiteral(v: Int) {
def cast: ZeroOrOneLiteral = {
require(v == 0 || v == 1, "0 or 1 accepted only")
Refined.unsafeApply(v)
}
}
var b: ZeroOrOneLiteral = 1
for (i <- 0 to 10)
b = i.cast
答案 1 :(得分:1)
如果还有人跟着,我有答案。是的,这是可能的。
我最近为singleton-ops library做出了贡献,并创建了TwoFace
和Checked
类型。
TwoFace.XXX[T]
,其中XXX
可以是Int
,String
等,是一个拥有T
类型和运行时值的值类。如果在编译时类型是已知的,则T
将拥有文字类型,并可用于编译时操作和检查。如果该值不是编译时文字,则T
将回退到其扩展类型(例如,scala.Int
),并且将使用该类的运行时值。