Попытка сохранить типы развернутыми при использовании refined
Я пытаюсь использовать refined для создания интеллектуальных конструкторов на основе примитивов и избегать обертки, поскольку одни и те же типы могут использоваться в больших коллекциях. Я правильно это делаю? Кажется, работает, но немного непонятно
type ONE_Pred = = MatchesRegex[W....
type ONE = String @@ ONE_Pred
type TWO_Pred = OneOf[...
type TWO = String @@ TWO_PRED
а потом
case class C(one:ONE, two:TWO)
object C {
def apply(one:String, two:String):Either[String, C] =
(
refineT[ONE_Pred](one),
refineT[TWO_Pred](two)
).mapN(C.apply)
}
1 ответ
Решение
Refined
имеет механизм для создания сопутствующих объектов, для которых уже определены некоторые утилиты:
type ONE = String @@ MatchesRegex["\\d+"]
object ONE extends RefinedTypeOps[ONE, String]
Обратите внимание, что:
- Вам не нужно указывать тип предиката отдельно
- Он работает как с бесформенными тегами, так и с улучшенными собственными новыми типами. Вкус, который вы получаете, основан на структуре
type ONE
.
Вы получаете:
ONE("literal")
как альтернативаrefineMT
/refineMV
ONE.from(string)
как альтернативаrefineT
/refineV
ONE.unapply
так что ты можешь сделатьstring match { case ONE(taggedValue) => ... }
ONE.unsafeFrom
когда ваш единственный вариант - выбросить исключение.
С помощью этих "компаньонов" можно писать гораздо более простой код без необходимости упоминания каких-либо типов предикатов:
object C {
def apply(one: String, two: String): Either[String, C] =
(ONE.from(one), TWO.from(two)).mapN(C.apply)
}
(пример в scastie, использование 2.13 с собственными типами литералов)