这是我认为人们通常想在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]
,我无法辨别如何从ClassTag[T]
到Reads[T]
。
是否可以像这样任意传播类型信息?如果是这样,怎么样?或者我的期望太高,这是不可能的,这就是为什么我找不到任何例子?
答案 0 :(得分:5)
这不是类型擦除问题。您可以将类型参数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]
,尽管有不同的例外。
我认为混淆的根源可能是错误:
<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 {
^
第二个错误是由第一个错误引起的(编译器可能已经停在那里),因此第二个错误在这种情况下没有帮助。
答案 1 :(得分:1)
您应该将隐式Reads
传递给解析方法:
def parse[T:Reads](json: JsValue): T = {
json.validate[T] match {
case JsSuccess(x, _) => x
case JsError(errors) => throw new MyException(errors.toString)
}
}
由于类型擦除
,此代码无法编译
不,如果你尝试编译它,你会得到类似的东西:&#34;找不到隐含的Reads [T] for parse&#34;