Использование чтения upickle в макросе Scala 3

Попробуйте написать общий макрос для десериализации кейс-классов, используя uPickle read в Scala 3:

inline def parseJson[T:Type](x: Expr[String])(using Quotes): Either[String, Expr[T]] = '{
  try 
    Right(read[T]($x.toString))
  catch  
    case e: Throwable => Left(s"Deserialization error: ${e.getMessage}") 
}

получить ошибку:

  Right(read[T]($x.toString))
        ^^^^^^^^^^^^^^^^^^^^
missing argument for parameter evidence$3 of method read in trait Api: (implicit evidence$3: upickle.default.Reader[T]): T

Я использую чтение uPickle для нескольких классов случаев, есть ли решение с меньшим количеством шаблонного кода? Спасибо за любую помощь!

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам нужно:

  1. разрешить неявное и поместить найденное значение в Expr - вы можете развернуть макрос внутри inline def (точно так же, как макросы вампиров из Scala 2), но НЕ когда вы создаете выражения с помощью '{}, тогда вам необходимо разрешить все неявные выражения
  2. return Expr[Either[Throwable, T]] — при создании тела макроса Scala 3 все возвращаемое значение должно быть Expr, иначе вы не сможете вывести его из кавычек внутри ${} (оно может работать как значение, возвращаемое помощником, который превратит его в Expr, но ${} принимает только один вызов чего-то, определенного в области верхнего уровня)
  3. отделите тело определения макроса Expr => Expr от его расширения - вы не можете написать "просто" inline def something[T: Type](a: Expr[T])(using Quotes): Expr[T] = ... - тело макроса - это (нестрочный) def, принимающий Type и Expr и Quotes и возвращающий один Expr. inline def должен заключить в кавычки одиночный Expr с помощью ${}... или просто быть обычным определением, которое можно скопировать на сайт вызова и разрешить там. Но тогда он не выводит из кавычек никаких Exprs

Итак, это либо:

// Quotes API requires separate inline def sth = ${ sthImpl }
// and def sthImpl[T: Type](a: Expr[...])(using Quotes): Expr[...]

inline def parseJson[T](x: String)(using r: Reader[T]): Either[Throwable, T] =
  ${ parseJsonImpl[T]('x)('r) }

// Since it builds a complete TASTy, it cannot "defer" implicit
// resolution to callsite. It either already gets value to put
// into using, or has to import quotes.*, quotes.reflect.* and
// then use Expr.summon[T].getOrElse(...)

def parseJsonImpl[T:Type](
  x: Expr[String]
)(
  reader: Expr[Reader[T]]
)(using Quotes): Expr[Either[String, T]] = '{
  try 
    Right(read[T]($x)(using $reader))
  catch  
    case e: Throwable => Left(s"Deserialization error: ${e.getMessage}") 
}

или

// inline def NOT using quotation API - NO Quotes, NO '{}

inline def parseJson[T: Reader](x: String): Either[String, T] = {
  try 
    // Here, you can use something like a "vampyre macros" and 
    // let the compiler expand macros at the call site
    Right(read[T](x))
  catch  
    case e: Throwable => Left(s"Deserialization error: ${e.getMessage}") 
}

Большое спасибо! Дополнительно (при наличии r: Reader[T]) необходимо во втором примере.

RobertJo 22.05.2024 08:48

Вы правы, я исправил ответ.

Mateusz Kubuszok 22.05.2024 10:05

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