如何使用Scala'确保类型安全;当使用相同的谓词进行细化时,s细化库
我不熟悉scala和精化库,但我正在尝试基于UUID创建两种精化类型 为此,我做了以下工作(注意:本例中的Uuid来自eu.timepit.defined.string.Uuid): 但是,这似乎只会创建别名,因此不存在类型安全性 所以如果我有一个像如何使用Scala'确保类型安全;当使用相同的谓词进行细化时,s细化库,scala,newtype,refinement-type,refined,Scala,Newtype,Refinement Type,Refined,我不熟悉scala和精化库,但我正在尝试基于UUID创建两种精化类型 为此,我做了以下工作(注意:本例中的Uuid来自eu.timepit.defined.string.Uuid): 但是,这似乎只会创建别名,因此不存在类型安全性 所以如果我有一个像Product(a UuidA,b UuidB)这样的构造函数 接着做了这样的事情: val myUuid: UuidA = "9f9ef0c6-b6f8-11ea-b3de-0242ac130004" val Product =
Product(a UuidA,b UuidB)这样的构造函数
接着做了这样的事情:
val myUuid: UuidA = "9f9ef0c6-b6f8-11ea-b3de-0242ac130004"
val Product = Product(myUuid, myUuid)
它将正确编译和运行。是否有办法确保情况并非如此?如果一个变量被创建为一种类型,我如何使它只作为特定的细化类型使用,即使类型基本相同?最简单的方法是引入不同的数据类型
case class UuidA(value: String Refined UuidPredicate)
case class UuidB(value: String Refined UuidPredicate)
您不能使UuidA
,UuidB
扩展AnyVal
,因为defined
已经扩展了AnyVal
,Scala不允许嵌套值类
如果您希望避免使用UuidA
,UuidB
包装的运行时开销,您可以尝试@newtype
作为@LuisMiguelMejíaSuárez的建议
import io.estatico.newtype.macros.newtype
@newtype case class UuidA(value: String Refined UuidPredicate)
@newtype case class UuidB(value: String Refined UuidPredicate)
或者尝试添加更多标记
import eu.timepit.refined.api.Refined
import eu.timepit.refined.string.Uuid
import eu.timepit.refined.auto._
import shapeless.tag
import shapeless.tag.@@
type UuidPredicate = Uuid
type UuidString = Refined[String, UuidPredicate]
type TagA
type TagB
type UuidA = UuidString @@ TagA
type UuidB = UuidString @@ TagB
case class Product(a: UuidA, b: UuidB)
val myUuid: UuidA = tag[TagA][UuidString]("9f9ef0c6-b6f8-11ea-b3de-0242ac130004")
// val product = Product(myUuid, myUuid) // doesn't compile
val myUuid1: UuidB = tag[TagB][UuidString]("9f9ef0c6-b6f8-11ea-b3de-0242ac130004")
val product1 = Product(myUuid, myUuid1) // compiles
您需要一个不确定这两个库在一起发挥得有多好的示例。顺便说一句,快速免责声明所有这些都是非常高级的东西,如果你对这门语言不熟悉,你可能会有点不舒服。@LuisMiguelMejíaSuárez
newtype
引入了宏注释(前面扩展了,case类替换为类型和对象)和defined
引入了隐式def宏(稍后展开,转换String=>String经过优化…
),因此不应该出现问题。
import eu.timepit.refined.api.Refined
import eu.timepit.refined.string.Uuid
import eu.timepit.refined.auto._
import shapeless.tag
import shapeless.tag.@@
type UuidPredicate = Uuid
type UuidString = Refined[String, UuidPredicate]
type TagA
type TagB
type UuidA = UuidString @@ TagA
type UuidB = UuidString @@ TagB
case class Product(a: UuidA, b: UuidB)
val myUuid: UuidA = tag[TagA][UuidString]("9f9ef0c6-b6f8-11ea-b3de-0242ac130004")
// val product = Product(myUuid, myUuid) // doesn't compile
val myUuid1: UuidB = tag[TagB][UuidString]("9f9ef0c6-b6f8-11ea-b3de-0242ac130004")
val product1 = Product(myUuid, myUuid1) // compiles