在scala中进行隐式转换遇到麻烦 [英] Having trouble with implicit conversion in scala

查看:98
本文介绍了在scala中进行隐式转换遇到麻烦的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

具有此代码

case class Workspace(ident: Long, name: String)
case class Project(ident: Long, name: String)

implicit def workspaceJSON: JSONR[Workspace] = new JSONR[Workspace] {
  def read(json: JValue) =
    Workspace.applyJSON(field[Long]("id"), field[String]("name"))(json)
}

implicit def projectJSON: JSONR[Project] = new JSONR[Project] {
  def read(json: JValue) =
    Project.applyJSON(field[Long]("id"), field[String]("name"))(json)
}

def parseEnt[T: JSONR](json: JValue): Either[String, T] =
  fromJSON[T](json).toEither.left.map{ _.toString }

def fetchProjects(ws: Workspace): Either[String, Project] = {
  parseEnt(parse("some text"))
}

使用

case class Workspace(ident: Long, name: String)
case class Project(ident: Long, name: String)

implicit def workspaceJSON: JSONR[Workspace] = new JSONR[Workspace] {
  def read(json: JValue) =
    Workspace.applyJSON(field[Long]("id"), field[String]("name"))(json)
}

implicit def projectJSON: JSONR[Project] = new JSONR[Project] {
  def read(json: JValue) =
    Project.applyJSON(field[Long]("id"), field[String]("name"))(json)
}

def parseEnt[T: JSONR](json: JValue): Either[String, T] =
  fromJSON[T](json).toEither.left.map{ _.toString }

def fetchProjects(ws: Workspace): Either[String, Project] = {
  parseEnt(parse("some text"))
}

parseEnt(parse("some text"))上编译失败

ambiguous implicit values:  both method taskJSON in class Fetcher of type =>
Fetcher.this.JSONR[types.Task]  and method workspaceJSON in class Fetcher of type =>
Fetcher.this.JSONR[Fetcher.this.Workspace]  match expected type Fetcher.this.JSONR[T]

有没有办法确保scala,在这种情况下,我想将变量T键入为Project,然后选择projectJSON函数对其进行解析?或者,如果我做错了,那怎么做才正确呢?

解决方案

编译器正在尝试自动推断类型T,该类型必须是可以从String开始生成的类型(或多或少,但此处不重要)

不幸的是,它无法成功,因为您要提供从StringProjectWorkspace的多个隐式转换.一种简单的解决方案是明确指出您要生成的类型:

parseEnt[Project](parse("some text"))

此模式在序列化类型类中相当普遍,在该类中,您将多个特定类型映射到通用类型(在本例中为String).

Having this code

case class Workspace(ident: Long, name: String)
case class Project(ident: Long, name: String)

implicit def workspaceJSON: JSONR[Workspace] = new JSONR[Workspace] {
  def read(json: JValue) =
    Workspace.applyJSON(field[Long]("id"), field[String]("name"))(json)
}

implicit def projectJSON: JSONR[Project] = new JSONR[Project] {
  def read(json: JValue) =
    Project.applyJSON(field[Long]("id"), field[String]("name"))(json)
}

def parseEnt[T: JSONR](json: JValue): Either[String, T] =
  fromJSON[T](json).toEither.left.map{ _.toString }

def fetchProjects(ws: Workspace): Either[String, Project] = {
  parseEnt(parse("some text"))
}

Which fails to compile on parseEnt(parse("some text")) with

ambiguous implicit values:  both method taskJSON in class Fetcher of type =>
Fetcher.this.JSONR[types.Task]  and method workspaceJSON in class Fetcher of type =>
Fetcher.this.JSONR[Fetcher.this.Workspace]  match expected type Fetcher.this.JSONR[T]

Is there a way to assure scala, that in this case I want type variable T to be a Project and choose projectJSON function to parse it? Or if I'm doing it wrong, then how do it in right way?

解决方案

The compiler is trying to automatically infer the type T, which must be something that it can be produced starting from a String (more or less, but details an unimportant here)

Unfortunately it can't succeed, since you're providing multiple implicit conversions going from String to Project and Workspace. The simple solution is to explicitly indicate the type you're trying to produce:

parseEnt[Project](parse("some text"))

This pattern is fairly common with serialization type classes, where you are mapping multiple specific types to a generic one (String in this case).

这篇关于在scala中进行隐式转换遇到麻烦的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆