2015-12-07 9 views
6

Sono abbastanza nuovo in Scala e ho cercato di imparare e comprendere conversioni e parametri impliciti e ho riscontrato uno scenario che trovo confuso.Parametro ed ereditarietà del costruttore di classi astratte implicite in Scala

Per contesto, sto utilizzando Scaldi per eseguire l'iniezione di dipendenza in un'applicazione Akka e vorrei che più attori iniettabili ereditassero da una classe astratta. Credo di non essere in grado di rendere la classe astratta un tratto proprio perché è necessario rendere disponibile un implicito Injector tramite un argomento del costruttore per sfruttare il framework.

Un esempio molto artificiosa che presenta il comportamento che sto vedendo è la seguente:

class SecretSauce {} 

abstract class Base(implicit secretSauce: SecretSauce) {} 

class Concrete extends Base {} 

object Example extends App { 
    ... // Setup Actor system, etc, etc 
    implicit val secretSauce: SecretSauce = new SecretSauce() 
} 

mi aspettavo cose a lavorare, ma invece ottengo un errore di compilazione:

Unspecified value parameter secretSauce. 
class Concrete extends Base { 
      ^

Se io aggiungere il parametro implicito alla classe concreta, come tale, le cose funzionano:

class Concrete(implicit secretSauce: SecretSauce) extends Base {} 

I t la mia confusione deriva da come funzionano i parametri impliciti - in situazioni come quella che sto descrivendo, non sono ereditate da classi di bambini? Qualcuno può ELI5 cosa sta succedendo nel mio esempio o mi indica un riferimento che può aiutare a chiarire le cose?

Grazie!

risposta

2

Le regole esatte che determinano dove il compilatore Scala cerca impliciti sono un po 'complicato, ma nella maggior parte dei casi è necessario solo pensare a due posti valori impliciti possono provenire da:

  1. l'ambito corrente.
  2. Gli oggetti associati per tutti i tipi coinvolti.

Ciò significa che questo compilerà:

class SecretSauce {} 

object SecretSauce { 
    implicit val secretSauce: SecretSauce = new SecretSauce() 
} 

abstract class Base(implicit secretSauce: SecretSauce) {} 

object Example extends App { 
    class Concrete extends Base {} 
} 

O questo:

class SecretSauce {} 

abstract class Base(implicit secretSauce: SecretSauce) {} 

object Example extends App { 
    implicit val secretSauce: SecretSauce = new SecretSauce() 

    class Concrete extends Base {} 
} 

Nella vostra versione, però, quando il compilatore arriva a questa linea:

class Concrete extends Base {} 

Saprà che è necessario trovare un valore implicito SecretSauce lue, e guarderà prima i valori impliciti nello scope a quella riga e successivamente nell'oggetto compagno SecretSauce (se esiste). Non lo trova, quindi si rifiuta di compilare il tuo codice.

+0

Ah, penso che la distillazione delle regole aiuti un bel po '. Perché un errore di compilazione non viene generato nel caso in cui l'argomento implicito è duplicato nella classe concreta? per esempio 'class Concrete (implicite secretSauce: SecretSauce) estende Base {}' Dal modo in cui l'ho impostato nel mio codice, il valore implicito non è ancora in ambito né è in un oggetto associato, giusto? La mia comprensione dell'ambito è qui fuori? – simonl

+0

@simonl Quando si aggiunge il parametro implicito al costruttore 'Concrete', implicito sarà nell'ambito della chiamata al costruttore padre. La sintassi di Scala per le definizioni e i costruttori di classi lo rende un po 'poco intuitivo, ma funziona. –

1

Il parametro implicito Get "risolto" da:

  • impliciti definiti nell'ambito corrente
  • importazioni espliciti
  • jolly importazioni

al fine di definire class Concrete per quanto ho capito , l'implicito deve essere definito o importato.

Trovo un'ottima spiegazione in this SO answer.