我对Scala有点新意,我正在尝试为我想使用的RESTful api编写通用客户端。我能够为我想要实例化我的客户端的特定案例类提供具体的Reads[T]
和Writes[T]
,但是编译器期望找到Reads[T]
和{{1对于任何类型,不仅仅是我使用的类型。一些代码来说明(我省略了不相关的部分):
我的通用客户:
Writes[T]
JsonSupprt Trait:
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"))
}
}
...
}
我只是实例化为trait JsonSupport {
implicit val accountFormat = Json.format[Account]
}
,但我收到了错误
RestModule[Account]("accounts",config)
当T只能是Account类型时,为什么编译器认为它需要一个类型为T的Writes?有什么方法可以解决这个问题吗?
答案 0 :(得分:1)
编译器不喜欢你正在做的事情的原因是如何解决implicit
参数的解决方法,更重要的是解决 的问题。< / p>
考虑一下代码段,
Object MyFunc {
def test()(implicit s: String): String = s
}
implicit
参数仅在调用函数时由参数解析,并且基本上被扩展为,
MyFunc.test()(resolvedImplicit)
在您的特定情况下,您实际上调用了需要implicit
的函数,因此它会在该时间点查找implicit
T
。由于它无法在范围内找到一个,因此无法编译。
要解决此问题,只需将implicit
参数添加到create
方法,即告知编译器在您调用create
而不是toJson
时解析它create
。
此外,我们可以使用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
时,如果implicit
为vals
,则用户无需导入或定义任何A
Int
或String
因为如果scala无法在当前范围内找到任何隐式定义,scala会自动在随播对象中查找。