[英]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]
的隐式值,则将其称为Foo
的Format
类型类的实例。
这种方法的优势在于,它为我们提供了一种不依赖子类型的方式来约束泛型类型(并在编译时检查了这些约束)的方法。 例如,标准库的String
不可能扩展Play(或任何其他库)可能提供的某种Jsonable
特性,因此我们需要某种方式说“我们知道如何将String
编码为JSON”,但这并不能实现。涉及使String
成为我们自己定义的某些特征的子类型。
在Play JSON中,您可以通过定义隐式Format
实例来做到这一点,而Play本身会为您提供许多实例(例如,如果T
有一个实例,则Seq[T]
会给您一个实例)。 JsValue
上的validate
方法的类型参数Seq[T]
在这种情况下为Seq[T]
)需要这些实例之一(实际上是Format
, Reads
的子类型,但在这里并不十分相关),并且除非编译器可以找到,否则它不会编译该实例。
您可以通过将约束添加到您自己的通用方法中来提供此实例:
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.