Domanda

La domanda è: perché il seguente codice non funziona con l'inferenza del tipo (di seguito è una sessione REPT da dimostrare) e può essere risolta? Più specificamente, in che modo è diverso dall'uso di canbuildfrom che il compilatore utilizza per inferire il tipo di ritorno?

Dato questo codice:

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)
    }
}

Ho questa sessione in 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 
È stato utile?

Soluzione

> trait UrlLike[T] {

trait UrlLike[+T] {

Altri suggerimenti

Posso capire perché ti aspetteresti che funzioni, ma, ovviamente, il tipo inferencer non sta usando il tipo di ritorno per dedurre T. Mi aspetterei anche io.

Per quanto riguarda l'ambiguità, CanBuildFrom Evita di essere ambiguo semplicemente non definendo tutto allo stesso "livello". Ad esempio, questo risolve il problema dell'ambiguità:

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}
}

Tuttavia, lo farà non Fai funzionare il tipo di inferenza come vuoi:

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

Il che indica ovviamente T Inferenza senza prendere in considerazione il tipo di ritorno.

Per quanto riguarda qualsiasi ambiguità implicita, il la regola è (da Scala2.8):

Quando si confrontano due diverse alternative applicabili di un metodo sovraccarico o di un metodo implicito:

  • ottiene un punto per Avere argomenti più specifici,
  • e un altro punto per essere definito in una sottoclasse adeguata.

Un alternativo "vince" su un altro se ottiene un numero maggiore di punti in questi due confronti.
Ciò significa in particolare che se le alternative hanno tipi di argomenti identici, quello che viene definito in una sottoclasse vince.

Non credo che gli implichi in giro URL o URI Ottieni una serie diversa di punti seguendo quei criteri.

Potrebbe non essere ovvio dal rapporto di errore che stai vedendo, ma tutti e tre gli impliciti definiti in oggetto Urlike stanno contribuendo all'ambiguità (ad esempio, prova a commentare la definizione di URI e vedrai l'ambiguità segnalata come essere tra STR e URL).

Il motivo dell'ambiguità è che il parametro di tipo T di Urlsupport.url è delimitato solo dal requisito secondo cui è disponibile un'istanza Urlike implicita. String, URL e URI soddisfano tutti quel requisiti ugualmente bene grazie alle istanze Urlike fornite dai tre oggetti impliciti. Il compilatore non sceglierà uno di quelli per te arbitrariamente, quindi riporta un'ambiguità.

A meno che, ovviamente, non risolva l'ambiguità specificando esplicitamente l'argomento del tipo, come hai fatto nelle ultime due interazioni REPL.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top