Как обеспечить безопасность типов с помощью библиотеки Scala Refined при использовании одного и того же предиката для уточнения

Я новичок в 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)

Он будет компилироваться и работать правильно. Есть ли способ убедиться, что это не так? Если переменная создается как один тип, как я могу сделать так, чтобы она использовалась только как конкретный уточненный тип, даже если типы в основном одинаковы?

1 ответ

Решение

Самый простой - ввести разные типы данных

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

Вы не можете сделать UuidA, UuidB расширять AnyVal потому как Refined уже распространяется 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
Другие вопросы по тегам