scala implicit-conversion ambiguity

scala - Valores implícitos ambiguos



implicit-conversion ambiguity (2)

El problema es que estás haciendo invariante el tipo A genérico. En su lugar, esto debería ser covariante. Así que esto debe ser implementado como sigue

case class Foo(baz: String) case class Bar(baz: String) // This `+` ↓ is the only difference class Reads[+A] { def read(s: String): A = throw new Exception("not implemented") } implicit val fooReads = new Reads[Foo] implicit val barReads = new Reads[Bar] def convert[A](s: String)(implicit reads: Reads[A]): A = reads.read(s) def f(s: String): Foo = convert(s)

Consulte http://docs.scala-lang.org/tutorials/tour/variances.html para obtener más información.

He estado pensando que entiendo las implicaciones de Scala hasta hace poco enfrenté un problema extraño.

En mi aplicación tengo varias clases de dominio

case class Foo(baz: String) case class Bar(baz: String)

Y una clase que es capaz de construir objetos de dominio a partir de una cadena. Podría ser subclasificado para hacer deserialización real, no importa.

class Reads[A] { def read(s: String): A = throw new Exception("not implemented") }

A continuación, hay deserializadores implícitos.

implicit val fooReads = new Reads[Foo] implicit val barReads = new Reads[Bar]

Y un ayudante para convertir cadenas en una de las clases de dominio.

def convert[A](s: String)(implicit reads: Reads[A]): A = reads.read(s)

Desafortunadamente, cuando se trata de usarlo

def f(s: String): Foo = convert(s)

Recibo errores de compilación como

error: ambiguous implicit values: both value fooReads of type => Reads[Foo] and value barReads of type => Reads[Bar] match expected type Reads[A] def f(s: String): Foo = convert(s) ^

Para mí el código parece simple y correcto. Reads[Foo] y Reads[Bar] son tipos completamente diferentes, ¿qué tiene de ambiguo?

El código real es mucho más complicado y utiliza play.api.libs.json pero esta versión simplificada es suficiente para reproducir el error.


La ambigüedad que está encontrando en su ejemplo es que no le dijo a Scalac cuál quería usar. Necesitas reemplazar tu código con

def f(s: String): Foo = convert[Foo](s)

para que pueda descubrir cuál usar. No se puede inferir del tipo de retorno de f . Tiene que ser explícito aquí.

Respuesta a comentar

Déjame jugar al abogado del diablo aquí.

trait Foo case class Bar(s: String) extends Foo case class Baz(s: String) extends Foo def f(s: String): Foo = convert(s)

¿Qué implícito utiliza asumiendo que hay uno definido tanto para Bar como para Baz ? Estoy seguro de que hay más casos diabólicos en las esquinas, pero este salta hacia mí.