这是我认为人们通常想要在Scala中做的事情,但是如果我能在任何地方找到一个例子我就该死.
由于类型擦除,此代码无法编译,但它演示了我正在尝试完成的任务:
def parse[T](json: JsValue): T = {
json.validate[T] match {
case JsSuccess(x, _) => x
case JsError(errors) => throw new MyException(errors.toString)
}
}
Run Code Online (Sandbox Code Playgroud)
我看到类型信息从擦除中保留的方式是添加一个隐式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)
}
}
Run Code Online (Sandbox Code Playgroud)
但是......现在怎么样?如果该validate方法采用ClassTag参数,我想我可以直接传递它:
json.validate(ct)
Run Code Online (Sandbox Code Playgroud)
...但它没有,它需要隐含的Reads[T],我无法辨别如何从a ClassTag[T]到a Reads[T].
是否有可能像这样任意传播类型信息?如果是这样,怎么样?或者我的期望太高,这是不可能的,这就是为什么我找不到任何例子?
这不是类型擦除问题.您可以将类型参数传递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)
}
}
Run Code Online (Sandbox Code Playgroud)
这消除了:
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)
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,此方法或多或少等同于写入json.as[T],尽管有不同的例外.
我想混淆的根源可能是错误:
<console>:16: error: type mismatch;
found : x.type (with underlying type Any)
required: T
case JsSuccess(x, _) => x
^
Run Code Online (Sandbox Code Playgroud)
但第一个错误实际上解释了问题:
<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 {
^
Run Code Online (Sandbox Code Playgroud)
第二个错误是由第一个错误引起的(编译器可能已经停在那里),因此在这种情况下第二个错误没有帮助.