Дуби не может найти или создать экземпляр Read для типа T - PullRequest
2 голосов
/ 24 октября 2019

Я использую doobie для запроса некоторых данных, и все работает нормально, например:

case class Usuario(var documento: String, var nombre: String, var contrasena: String)

  def getUsuario(doc: String) =
     sql"""SELECT documento, nombre, contrasena FROM "Usuario" WHERE "documento" = $doc"""
      .query[Usuario]
      .option
      .transact(xa)
      .unsafeRunSync()

Но если я объявлю функцию с ограничением типа, как это:

 def getOption[T](f: Fragment): Option[T] = {
    f.query[T]
     .option
     .transact(xa)
     .unsafeRunSync()

}

Я получил эти ошибки:

Error:(42, 12) Cannot find or construct a Read instance for type:
  T
This can happen for a few reasons, but the most common case is that a data
member somewhere within this type doesn't have a Get instance in scope. Here are
some debugging hints:
- For Option types, ensure that a Read instance is in scope for the non-Option
  version.
- For types you expect to map to a single column ensure that a Get instance is
  in scope.
- For case classes, HLists, and shapeless records ensure that each element
  has a Read instance in scope.
- Lather, rinse, repeat, recursively until you find the problematic bit.
You can check that an instance exists for Read in the REPL or in your code:
  scala> Read[Foo]
and similarly with Get:
  scala> Get[Foo]
And find the missing instance and construct it as needed. Refer to Chapter 12
of the book of doobie for more information.
    f.query[T].option.transact(xa).unsafeRunSync()

Error:(42, 12) not enough arguments for method query: (implicit evidence$1: doobie.util.Read[T], implicit h: doobie.LogHandler)doobie.Query0[T].
Unspecified value parameter evidence$1.
    f.query[T].option.transact(xa).unsafeRunSync()

Кто-нибудь знает, как сделать то, что я хочу? Я думаю, что это что-то имеет последствия, но я не знаю, как это исправить.

1 Ответ

2 голосов
/ 24 октября 2019

Чтобы doobie мог преобразовать результат запроса SQL в ваш класс дел, ему нужен экземпляр Read класс типов в области видимости.

Например, для Usuario требуется экземпляр Read[Usuario]. К счастью, doobie может получить классы типов для типов из классов типов , которые он уже знает, например String, поэтому в большинстве случаев нам не нужносоздайте их явно.

В вашем случае вы хотите создать метод getOption, который имеет параметр типа T, что означает, что компилятор не знает, для какого класса типов из которыхтип для поиска.

Вы можете исправить это очень просто, просто добавив контекстную привязку для Read к вашему типу (например, T: Read или добавив неявный параметр). Это означает, что ваш метод передаст «запрос» для разрешения класса типов позже во время компиляции, когда конкретный тип T будет уже известен.

Итак, ваш фиксированныйметод будет:

def getOption[T: Read](f: Fragment): Option[T] = {
    f.query[T]
     .option
     .transact(xa)
     .unsafeRunSync()

или с неявным параметром:

def getOption[T](f: Fragment)(implicit read: Read[T]): Option[T] = {
    f.query[T]
     .option
     .transact(xa)
     .unsafeRunSync()
...