2016-11-17 1 views
3

Le code:Pourquoi aucune vue implicite n'est trouvée lorsque la conversion eta et la spécification des paramètres de type permettent de trouver une vue implicite?

object Test { 
    import scala.language.implicitConversions 

    case class C1() {} 
    case class C2() {} 

    implicit def c1ToC2(in: C1): C2 = C2() 

    def from[A, B](in: A)(implicit f: A => B): B = f(in) 

    def fails(): Future[C2] = { 
    val future: Future[C1] = Future.successful(C1()) 
    future.map(from) // this line fails to compile! 
    } 

    def compiles1(): Future[C2] = { 
    val future: Future[C1] = Future.successful(C1()) 
    future.map(x => from(x)) 
    } 

    def compiles2(): Future[C2] = { 
    val future: Future[C1] = Future.successful(C1()) 
    future.map(from[C1, C2]) 
    } 
} 

Dans cet exemple, seule la méthode fails ne parvient pas à compiler. Le message d'erreur est:

Error:(23, 16) No implicit view available from A => B. future.map(from)

Je suis confus au sujet de pourquoi pas de vue implicite se trouve. Sur la base des compiles1 et compiles2 méthodes, à la fois compilera, il semble qu'il y ait est une vue implicite disponible de A => B.

ce qui se passe ici, et pourquoi les deux méthodes de compilesN, mais fails ne fait pas? Mes antécédents: J'apprends toujours Scala, alors il pourrait facilement y avoir quelque chose qui me manque. :)

Je suis sur Scala 2.11.8.

Répondre

6

Les tentatives du compilateur pour résoudre implicits avant eta-expansion de from en fonction, de sorte que les paramètres de type de from ne sont pas encore inférée lorsque vous l'appelez comme ceci:

future.map(from) 

compiles2 fonctionne évidemment parce que vous fournissez les paramètres de type sur votre propre. Lorsque vous appelez future.map(from[C1, C2]), le compilateur sait qu'il aura besoin d'un C1 => C2 implicite, parce que c'est ce que vous lui avez dit.

Avec compiles1, la différence est un peu plus subtile, mais elle provient du fait que future.map(from) et future.map(x => from(x)) sont en réalité des choses très différentes. Le premier utilise eta-expansion, qui échoue pour les raisons mentionnées ci-dessus. Avec future.map(x => from(x)), il n'y a pas d'eta-expansion qui se passe. Au lieu de cela, vous avez une fonction anonyme qui appelle simplement from au lieu de eta-expansion. Par conséquent, le compilateur peut déduire le type de x, qui nous indique que x est un C1 (dans ce cas), et il peut trouver la conversion implicite c1ToC2 qui satisfait les paramètres de type de from tout en résolvant le type de retour implicite et final la méthode, Future[C2].