Как обеспечить безопасность типов с помощью библиотеки 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