1

我是 scala 和精炼库的新手,但我正在尝试基于 UUID 创建两种精炼类型。

为此,我这样做了(注意:本例中的 Uuid 来自 eu.timepit.refined.string.Uuid):

type UuidPredicate = Uuid

type UuidA = String Refined UuidPredicate
type UuidB = String Refined UuidPredicate

但是,这似乎只创建别名,因此没有类型安全性。

因此,如果我有一个类似的构造函数Product(a UuidA, b UuidB) 并继续执行以下操作:

val myUuid: UuidA = "9f9ef0c6-b6f8-11ea-b3de-0242ac130004"
val Product = Product(myUuid, myUuid)

它将正确编译和运行。有没有办法确保不是这种情况?如果一个变量被创建为一种类型,我怎样才能使它只用作那个特定的细化类型,即使类型基本相同?

4

1 回答 1

2

最简单的就是引入不同的数据类型

case class UuidA(value: String Refined UuidPredicate)
case class UuidB(value: String Refined UuidPredicate)

你不能 make UuidA, UuidBextendAnyVal因为Refined已经 extendsAnyVal并且 Scala 不允许嵌套值类。

如果您希望避免使用 包装的运行时开销UuidAUuidB您可以@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
于 2020-06-25T18:02:21.190 回答