我认为这是人们通常希望在Scala中做的事情,但如果在任何地方都可以找到一个示例,我该死的。
这段代码由于类型擦除而无法编译,但是它演示了我要完成的工作:
def parse[T](json: JsValue): T = {
json.validate[T] match {
case JsSuccess(x, _) => x
case JsError(errors) => throw new MyException(errors.toString)
}
}
我所看到的从擦除中保留类型信息的方式是添加一个隐式ClassTag
参数:
def parse[T](json: JsValue)(implicit ct: ClassTag[T]): T = {
json.validate[T] match {
case JsSuccess(x, _) => x
case JsError(errors) => throw new MyException(errors.toString)
}
}
但是...现在呢?如果该validate
方法带有ClassTag
参数,我想我可以直接传递它:
json.validate(ct)
...但不是,它需要一个隐式Reads[T]
,而且我无法辨别如何从aClassTag[T]
到a Reads[T]
。
这样可以任意传播类型信息吗?如果是这样,怎么办?还是我的期望太高了,这是不可能的,这就是为什么我找不到任何示例?
这不是类型擦除问题。您可以将type参数传递T
给validate
并且尚未将其擦除。问题是您需要Reads[T]
范围内的隐式可用。您可以通过将其添加为上下文绑定来轻松解决此问题:
def parse[T: Reads](json: JsValue): T = {
json.validate[T] match {
case JsSuccess(x, _) => x
case JsError(errors) => throw new MyException(errors.toString)
}
}
这种去糖可以:
def parse[T](json: JsValue)(implicit r: Reads[T]): T = {
json.validate[T] match {
case JsSuccess(x, _) => x
case JsError(errors) => throw new MyException(errors.toString)
}
}
请注意json.as[T]
,尽管有不同的例外,此方法或多或少等效于write。
我想混淆的根源可能是错误:
<console>:16: error: type mismatch;
found : x.type (with underlying type Any)
required: T
case JsSuccess(x, _) => x
^
但是第一个错误实际上解释了这个问题:
<console>:15: error: No Json deserializer found for type T. Try to implement an implicit Reads or Format for this type.
json.validate[T] match {
^
第二个错误是由第一个错误引起的(编译器应该已经在该位置停止了),因此第二个错误在这种情况下无济于事。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句