如何使用Scala'确保类型安全;当使用相同的谓词进行细化时,s细化库

如何使用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 =

我不熟悉scala和精化库,但我正在尝试基于UUID创建两种精化类型

为此,我做了以下工作(注意:本例中的Uuid来自eu.timepit.defined.string.Uuid):

但是,这似乎只会创建别名,因此不存在类型安全性

所以如果我有一个像
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