Scala 为编译时文字和 运行-time 变量优化了整数
Scala refined integer for both compile-time literal and run-time variable
我希望将变量限制为布尔整数表示形式(0 或 1),作为定义的输入。到目前为止,这可以通过两种方式实现,一种在运行时,一种在编译时,仅用于文字。
是否有可能以某种方式将两者结合起来,这样我就可以创建一个类型,在编译时拒绝超出范围的文字值,但也允许在运行时检查非文字输入?
运行时守卫
类似于此博客 post:
http://erikerlandson.github.io/blog/2015/08/18/lightweight-non-negative-numerics-for-better-scala-type-signatures/
/////////////////////////////
//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 refined 的创建者交换电子邮件后,这可能会在库本身中得到解决。我在 GitHub here 上打开了一个功能请求问题。如果以及何时使用此功能更新库,我将更新此问题。
您可以使用Refined.unsafeApply
跳过编译时检查。如果你想检查不安全的调用是 运行 次,你将不得不手动进行。例如,使用隐式 class:
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
如果还有人关注,我有一个答案。是的,这是可能的。
我最近为 singleton-ops library 做出了贡献,并创建了 TwoFace
和 Checked
类型来精确地执行此操作。
TwoFace.XXX[T]
,其中XXX
可以是Int
、String
等,是一个值class同时拥有T
] 和 运行-时间值。如果在编译时类型已知,则 T
将拥有文字类型并可用于编译时操作和检查。如果该值不是编译时文字,则 T
将回退到其扩展类型(例如 scala.Int
),并且 运行-时间值 class将被使用。
我希望将变量限制为布尔整数表示形式(0 或 1),作为定义的输入。到目前为止,这可以通过两种方式实现,一种在运行时,一种在编译时,仅用于文字。
是否有可能以某种方式将两者结合起来,这样我就可以创建一个类型,在编译时拒绝超出范围的文字值,但也允许在运行时检查非文字输入?
运行时守卫
类似于此博客 post: http://erikerlandson.github.io/blog/2015/08/18/lightweight-non-negative-numerics-for-better-scala-type-signatures/
/////////////////////////////
//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 refined 的创建者交换电子邮件后,这可能会在库本身中得到解决。我在 GitHub here 上打开了一个功能请求问题。如果以及何时使用此功能更新库,我将更新此问题。
您可以使用Refined.unsafeApply
跳过编译时检查。如果你想检查不安全的调用是 运行 次,你将不得不手动进行。例如,使用隐式 class:
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
如果还有人关注,我有一个答案。是的,这是可能的。
我最近为 singleton-ops library 做出了贡献,并创建了 TwoFace
和 Checked
类型来精确地执行此操作。
TwoFace.XXX[T]
,其中XXX
可以是Int
、String
等,是一个值class同时拥有T
] 和 运行-时间值。如果在编译时类型已知,则 T
将拥有文字类型并可用于编译时操作和检查。如果该值不是编译时文字,则 T
将回退到其扩展类型(例如 scala.Int
),并且 运行-时间值 class将被使用。