繁体   English   中英

基于泛型的Scala函数返回类型

[英]Scala function return type based on generic

使用Scala泛型,我试图抽象Play应用程序中的一些常用功能。 函数返回带有从REST JSON服务反Seq的对象的Seq

def getPeople(cityName: String): Future[Seq[People]] = {
    getByEndpoint[People](s"http://localhost/person/$cityName")
}

def getPeople(): Future[Seq[Dog]] = {
    getByEndpoint[Dog]("http://localhost/doge")
}

使用泛型将获取和反序列化逻辑打包到单个函数中。

private def getByEndpoint[T](endpoint: String): Future[Seq[T]] = {

    ws.url(endpoint)
      .get()
      .map(rsp => rsp.json)
      .flatMap { json =>
        json.validate[Seq[T]] match {
          case s: JsSuccess[Seq[T]] =>
            Future.successful(s.get)
          case e: JsError =>
            Future.failed(new RuntimeException(s"Get by endpoint JSON match failed: $e"))
        }
      }

}

问题是我遇到了“ No Json deserializer found for type Seq[T]. Try to implement an implicit Reads or Format for this type. ”。 我确定我没有在Seq[T]正确使用T (至少根据我的C#/ Java内存),但是我找不到在Scala中正确使用T任何线索。 一切都按预期工作,而无需使用泛型。

Play JSON使用类型类来捕获有关哪些类型可以与JSON(反序列化)和从JSON(反序列化)以及如何进行的信息。 如果您在范围内具有类型Format[Foo]的隐式值,则将其称为FooFormat类型类的实例。

这种方法的优势在于,它为我们提供了一种不依赖子类型的方式来约束泛型类型(并在编译时检查了这些约束)的方法。 例如,标准库的String不可能扩展Play(或任何其他库)可能提供的某种Jsonable特性,因此我们需要某种方式说“我们知道如何将String编码为JSON”,但这并不能实现。涉及使String成为我们自己定义的某些特征的子类型。

在Play JSON中,您可以通过定义隐式Format实例来做到这一点,而Play本身会为您提供许多实例(例如,如果T有一个实例,则Seq[T]会给您一个实例)。 JsValue上的validate方法的类型参数Seq[T]在这种情况下为Seq[T] )需要这些实例之一(实际上是FormatReads的子类型,但在这里并不十分相关),并且除非编译器可以找到,否则它不会编译该实例。

您可以通过将约束添加到您自己的通用方法中来提供此实例:

private def getByEndpoint[T: Format](endpoint: String): Future[Seq[T]] = {
  ...
}

现在,随着T: Format语法您已指定必须有一个Format ,例如T (即使你不约束T以任何其他方式),因此编译器知道如何提供Format例如Seq[T] json.validate[Seq[T]]调用所需。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM