传播Scala类型参数

肖恩

我认为这是人们通常希望在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]

这样可以任意传播类型信息吗?如果是这样,怎么办?还是我的期望太高了,这是不可能的,这就是为什么我找不到任何示例?

迈克尔·扎亚克(Michael Zajac)

这不是类型擦除问题。您可以将type参数传递Tvalidate并且尚未其擦除。问题是您需要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] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章