Pregunta

La pregunta es por qué no funciona el siguiente código con inferencia de tipo (a continuación es una sesión de replica para demostrar), y se puede solucionar? Más específicamente, ¿en qué se diferencia esto del uso de CanBuildFrom que el compilador usa para inferir el tipo de retorno?

Dado este código:

object S {
    import java.net._

    trait UrlLike[T] {
      def url(s: String): T
    }

    object UrlLike {
      implicit object str extends UrlLike[String]{def url(s: String) = s}
      implicit object url extends UrlLike[URL]{def url(s: String) = new URL(s)}
      implicit object uri extends UrlLike[URI]{def url(s: String) = new URI(s)}
    }

    trait UrlSupport {
        val _url: String

        def url[T : UrlLike]: T = implicitly[UrlLike[T]].url(_url)
    }
}

Tengo esta sesión en el repl (2.8.1):

scala> :load c:\temp\UrlTest.scala
Loading c:\temp\UrlTest.scala...
defined module S

scala> import java.net._
import java.net._

scala> import S._
import S._

scala> new UrlSupport{val _url = "http://example.com"}
res0: java.lang.Object with S.UrlSupport = $anon$1@155bd22

scala> res0.url : String
<console>:14: error: ambiguous implicit values:
 both object uri in object UrlLike of type object S.UrlLike.uri
 and object url in object UrlLike of type object S.UrlLike.url
 match expected type S.UrlLike[T]
       res0.url : String
            ^

scala> res0.url : URL
<console>:14: error: ambiguous implicit values:
 both object uri in object UrlLike of type object S.UrlLike.uri
 and object url in object UrlLike of type object S.UrlLike.url
 match expected type S.UrlLike[T]
       res0.url : URL
            ^

scala> res0.url[String]
res3: String = http://example.com

scala> res0.url[URL]
res4: java.net.URL = http://example.com 
¿Fue útil?

Solución

> trait UrlLike[T] {

trait UrlLike[+T] {

Otros consejos

Puedo ver por qué esperarías que funcione, pero, obviamente, el tipo de inferencia no está usando el tipo de retorno para inferir T. También lo esperaría.

En cuanto a la ambigüedad, CanBuildFrom Evita ser ambiguo simplemente no definir todo en el mismo "nivel". Por ejemplo, esto resuelve el problema de ambigüedad:

trait LowPriorityImplicits {
  implicit object url extends UrlLike[URL]{def url(s: String) = new URL(s)}
  implicit object uri extends UrlLike[URI]{def url(s: String) = new URI(s)}
}

object UrlLike extends LowPriorityImplicits {
  implicit object str extends UrlLike[String]{def url(s: String) = s}
}

Sin embargo, lo hará no Haga que el tipo de inferencia funcione de la manera que desee:

scala> res0.url : URL
<console>:16: error: type mismatch;
 found   : String
 required: java.net.URL
       res0.url : URL
            ^

Lo que indica que obviamente hace T inferencia sin tener en cuenta el tipo de retorno.

Con respecto a cualquier ambigüedad implícita, el La regla es (desde Scala2.8):

Al comparar dos alternativas aplicables diferentes de un método sobrecargado o de un implícito, cada método:

  • Obtiene un punto para tener argumentos más específicos,
  • y otro punto para siendo definido en una subclase adecuada.

Una alternativa "gana" sobre otra si obtiene un mayor número de puntos en estas dos comparaciones.
Esto significa en particular que si las alternativas tienen tipos de argumentos idénticos, el que se define en una subclase gana.

No creo que los implicados URL o URI Obtenga un conjunto diferente de puntos después de esos criterios.

Puede que no sea obvio por el informe de error que está viendo, pero los tres implicados definidos en el objeto Urllike están contribuyendo a la ambigüedad (por ejemplo, intente comentar la definición de URI y verá que la ambigüedad se informó como entre str y url).

La razón de la ambigüedad es que el parámetro T de Urlsupport.Url solo está limitado por el requisito de que haya una instancia de urllike implícita disponible para ello. String, URL y URI satisfacen ese requisito igualmente bien gracias a las instancias de Urllike proporcionadas por sus tres objetos implícitos. El compilador no va a elegir uno de esos para usted arbitrariamente, por lo que informa una ambigüedad.

A menos que, por supuesto, resuelva la ambigüedad al especificar explícitamente el argumento de tipo, como lo ha hecho en las últimas dos de sus interacciones REPL.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top