2013-04-30 17 views
6

Sono un principiante alla Scala. Ho letto un paio di libri e ho letto alcuni tutorial online. Il mio primo progetto sta avendo problemi, quindi ho ridotto il codice alla cosa più semplice che può andare storta.Costruttori in scala con varargs

Ho cercato google e stack overflow per scala/constructors/varargs e ho letto un paio di tour di scala.

La (quasi) codice semplice è:

class Foo(val params: Int*) 
case class Foo1(val p: Int) extends Foo(p) 
case class Foo2(val p1: Int, val p2: Int) extends Foo(p1, p2) 

object Demo extends App { 
    override def main(args: Array[String]) { 
    val f = Foo2(1, 2) 
    f.p1 
    } 
} 

L'eccezione si verifica quando si accede p1 ed è

Exception in thread "main" java.lang.ClassCastException: scala.collection.mutable.WrappedArray $ ofInt non può essere lanciato a java.lang.Integer

Il ricorso al debugging con Eclipse, ho trovato un interessante proprietà: Se si guarda a variabili

f Foo2 (id=23) 
    p2 2 
    params WrappedArray$ofInt (id=33) 
     array (id=81)  
      [0] 1 
      [1] 2 

Quindi cosa è successo a p1?

Mi dispiace per voi preoccupanti con una domanda newbie

risposta

6

Non sei sbagliato, ma il compilatore è. Si cerca di ottenere p1 di p (nel tuo caso sarebbe cercare di ottenere Foo2.p1 fuori Foo.params):

def p1(): Int = scala.Int.unbox(Main$$anon$1$B.super.p()); 

che è ovviamente un errore, perché non può funzionare. Invece dovrebbe assegnare p1 nel ctor della sottoclasse.

Ho segnalato un errore: SI-7436.

+0

Woot. Il mio primo bug alla Scala. Ok grazie. Ho un lavoro in giro, ma apprezzo l'aiuto. Questo mi ha ricordato i blocchi di equivalenza di Fortran, o i record delle varianti Pascal. –

+0

Btw, 'classe X (val p: Int *)' non ha molto senso. Se vuoi avere accesso a 'p' dopo la costruzione di X usa solo una sequenza invece di varargs:' classe X (val p: Seq [Int]) 'o' classe X (p: Int *) {def params: Seq [Int] = p} '. – sschaef

1

non posso spiegarti/perché/Scala si confonde, ma le seguenti opere:

class Foo(p: Int, ps: Int*) 
case class Foo1(p1: Int) extends Foo(p1) 
case class Foo2(p1: Int, p2: Int) extends Foo(p1, p2) 

object Main extends App { 
    println(Foo1(1)) 
    println(Foo2(2, 3)) 
} 

Si noti inoltre che, quando si estende App , non si desidera eseguire l'override di main.

+0

Apprezzo il commento su App. Sono un principiante, quindi ho appena usato l'esempio Hello World in Eclipse. Grazie per il codice funzionante. Ho qualcosa che usa liste che funziona anche: il mio problema è di comprensione. Sfortunatamente sono molto preoccupato della "leggibilità" del codice, e l'intento della variabile param è di contenere tutti i parametri. Mi chiedo se questo è un bug di scala –

+0

Dopo aver letto il tuo commento penso che avrei dovuto menzionare che il codice precedente cambia anche la semantica del tuo esempio perché il costruttore di 'Foo' ora richiede almeno un argomento. Probabilmente no, ma questo dipende dal dominio del problema :) – fotNelton

0

Si dovrebbe avere uno sguardo al this comment e la risposta appena al di sopra di esso, penso che dovrebbe rispondere alla tua problema ;-)

+0

Grazie per la risposta. L'ho visto prima di pubblicare la domanda, ma non penso che sia la risposta corretta. In quella domanda la persona voleva passare un Any * params al costruttore. Non voglio farlo. Nel caso di Foo2 sto passando (p1, p2) ad un Any *, e per qualche strano motivo sta perdendo l'accesso alla variabile p1, e sostituendolo con una chiamata per ottenere parametri, quindi con un cast di classe. Si noti che nella domanda la persona non ha potuto ottenere il codice da compilare. Il mio compila e corre –