14

Scala-lang riferimento 5.5.1 e 6.6.1 mi ha dato l'impressione che un parametro di default sarebbe in grado di fare riferimento a una precedenza valutato uno:Come dovrebbero gli argomenti predefiniti di Scala fare riferimento a un argomento posizionale precedente?

class Test(val first: String, val second: String = first) 

ma da sperimentare sembra che l'unico modo per fare questo è quello di utilizzare la forma:

class Test(val first: String)(val second: String = first) 

e quindi definire un costruttore ausiliario o una classe guidata creazionale per evitare di specificare il secondo set di staffe durante la creazione. Non capisco davvero come funzioni questo secondo costruttore, sembra una funzione al curry, quindi posso immaginare che sia necessario valutare first indipendentemente da second, è corretto? Questa forma è necessaria o c'è dello zucchero sintetico che posso usare per modificare il primo costruttore nel fare ciò che voglio?

+0

Non esiste una (sotto) sezione 5.5.1 nella [Specifica lingua corrente di Scala] (http://www.scala-lang.org/sites/default/files/linuxsoft_archives/docu/files/ScalaReference.pdf) . Intendevi 5.1.1 ("Invocazioni costruttore")? – Philippe

+0

Sì avrebbe dovuto essere 5.1.1. Come @Travis Brown ha sottolineato la sezione 5.3 che definisce l'ambito dei parametri mentre vengono valutati spiegherebbe l'errore di compilazione. – MilesHampson

risposta

9

Come indicato da Travis Brown, in effetti si può solo fare riferimento a un argomento precedente in un'espressione predefinita quando proviene da un elenco di argomenti precedente (quindi è necessario currify).

Ora, per quanto riguarda il vostro caso d'uso particolare, gli argomenti predefiniti e l'overloading del metodo sono a volte due modi per ottenere la stessa cosa.

Penso che la soluzione più semplice per lo scenario è semplicemente definire Test come segue:

class Test(val first : String, val second : String) { 
    def this(f : String) = this(f, f) 
} 

Se si vuole rendere più complicato, un modo alternativo, utilizzando un oggetto associato:

class Test(val first : String)(val second : String = first) 
object Test { 
    def apply(f : String) = new Test(f) 
    def apply(f : String, s : String) = new Test(f)(s) 
} 

(Una piccola differenza è che ora si creano oggetti senza new.)

quello che Non può fare, è definirlo come:

class Test(val first : String)(val second : String = first) { 
    def this(f : String, s : String) = this(f)(s) 
} 

... perché la versione al curry si traduce in (tra le altre cose) un metodo con la stessa firma del contructor sovraccarico.

+0

Un buon punto sulla doppia definizione. – MilesHampson

7

dal 5,3 di the spec:

L'ambito di un parametro formale valore include tutti i successivi le sezioni dei parametri e il modello t.

metodi normali sono uguali, tra l'altro (da 4,6):

L'ambito di un valore formale nome di parametro x comprende tutti clausole parametri successive, nonché il ritorno metodo digitare e il corpo della funzione, se vengono assegnati.

cioè se hai un costruttore o un metodo ordinario, un nome di parametro di valore non è nel campo di applicazione nella propria clausola di parametro. Nella seconda versione il costruttore ha due clausole sui parametri e first è solo nell'ambito della seconda. Vedi 5.3 per maggiori dettagli su più clausole di parametro.

+0

Grazie, era quello che stavo cercando. – MilesHampson