Попытка сохранить типы развернутыми при использовании 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]

Обратите внимание, что:

  1. Вам не нужно указывать тип предиката отдельно
  2. Он работает как с бесформенными тегами, так и с улучшенными собственными новыми типами. Вкус, который вы получаете, основан на структуре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 с собственными типами литералов)

Другие вопросы по тегам