0

我对 Scala 有点陌生,我正在尝试为我想使用的 RESTful api 编写一个通用客户端。我能够为我想实例化我的客户端的具体案例类提供具体的Reads[T]和特定的案例类,但是编译器希望找到任何类型的和,而不仅仅是我正在使用的类型。一些代码来说明(我省略了不相关的部分):Writes[T]Reads[T]Writes[T]

我的通用客户:

class RestModule[T](resource: String, config: Config) ... with JsonSupport{
...
def create(item: T): Future[T] = {
    val appId = config.apiId
    val path = f"/$apiVersion%s/applications/$appId%s/$resource"

    Future {
      val itemJson = Json.toJson(item)
      itemJson.toString.getBytes
    } flatMap {
      post(path, _)
    } flatMap { response =>
      val status = response.status
      val contentType = response.entity.contentType

      status match {
        case Created => contentType match {
          case ContentTypes.`application/json` => {
            Unmarshal(response.entity).to[T]
          }
          case _ => Future.failed(new IOException(f"Wrong Content Type: $contentType"))
        }
        case _ => Future.failed(new IOException(f"HTTP Error: $status"))
      }
    }
...
}

JsonSupprt 特性:

trait JsonSupport {
    implicit val accountFormat = Json.format[Account]
}

我只是实例化,RestModule[Account]("accounts",config)但我得到了错误

Error:(36, 32) No Json serializer found for type T. Try to implement an implicit Writes or Format for this type.
  val itemJson = Json.toJson(item)
                           ^

当 T 只能是 Account 类型时,为什么编译器认为它需要对类型 T 的写入?有没有办法解决这个问题?

4

1 回答 1

1

编译器不喜欢你正在做的事情的原因是与如何implicit解析参数有关,更关键的是它们被解析时。

考虑片段,

Object MyFunc {
   def test()(implicit s: String): String = s
}

参数仅在调用函数时由implicit参数解析,并且基本上扩展为,

MyFunc.test()(resolvedImplicit)

在您的特定情况下,您实际上调用了需要的函数implicit,因此它会在那个时间点查找implicitan T。由于在范围内找不到它,因此无法编译。

为了解决这个问题,只需将implicit参数添加到create方法中,告诉编译器在调用时解决它,create而不是toJsoncreate.

此外,我们可以使用 scala 的隐式规则来获得您想要的行为。

让我们看看你的特质Reads

trait Reads[A] {
}

object MyFunc {
  def create[A](a: A)(implicit reads: Reads[A]): Unit = ???
}

正如我们之前所说,如果implicit在范围内,您可以调用它。但是,在这种特殊情况下,您已经预定义了读取,我们实际上可以将它放在伴随对象中,

object Reads {
  implicit val readsInt: Reads[Int] = ???
  implicit val readsString: Reads[String] = ???
}

这样create调用 when 时,用户不需要导入或定义任何implicit valswhen AisIntString因为 scala 如果在当前范围内找不到任何隐式定义,则会自动在伴随对象中查找任何隐式定义。

于 2016-02-29T18:40:00.880 回答