In breve, non sembra una buona idea utilizzare le case classes in questo modo. Ecco una spiegazione.
Controlliamo la dichiarazione della classe insieme a generata apply
e unapply
:
scala> case class A(a: Int, b: String)(c: String, d: Int)
defined class A
scala> A.apply _
res0: (Int, String) => (String, Int) => A = <function2>
scala> A.unapply _
res1: A => Option[(Int, String)] = <function1>
Si può vedere che, anche se apply
prende 4 argomenti in totale (curry), unapply
rigetti in mare secondo elenco.
Vediamo se siamo in grado di accedere ai membri della seconda lista:
scala> val a = A(1, "two")("three", 4)
a: A = A(1,two)
scala> a.a
res2: Int = 1
scala> a.c
<console>:11: error: value c is not a member of A
a.c
^
... no, non è un modo normale. Controlliamo un paio di altre proprietà:
scala> a.productArity
res4: Int = 2
scala> a.productIterator.toList
res5: List[Any] = List(1, two)
Ok, sembra che la seconda lista di argomenti sia praticamente ignorata. Scaviamo in:
scala> :javap A
...
public int a();
descriptor:()I
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #16 // Field a:I
4: ireturn
...
public java.lang.String b();
descriptor:()Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #21 // Field b:Ljava/lang/String;
4: areturn
...
public boolean equals(java.lang.Object);
descriptor: (Ljava/lang/Object;)Z
flags: ACC_PUBLIC
... //mentions only a and b:....
32: invokevirtual #32 // Method a:()I
35: aload 4
37: invokevirtual #32 // Method a:()I
40: if_icmpne 88
43: aload_0
44: invokevirtual #35 // Method b:()Ljava/lang/String;
47: aload 4
49: invokevirtual #35 // Method b:()Ljava/lang/String;
...
public A(int, java.lang.String, java.lang.String, int);
descriptor: (ILjava/lang/String;Ljava/lang/String;I)V
flags: ACC_PUBLIC
Code:
stack=2, locals=5, args_size=5
0: aload_0
1: iload_1
2: putfield #16 // Field a:I
5: aload_0
6: aload_2
7: putfield #21 // Field b:Ljava/lang/String;
10: aload_0
11: invokespecial #100 // Method java/lang/Object."<init>":()V
14: aload_0
15: invokestatic #106 // Method scala/Product$class.$init$:(Lscala/Product;)V
18: return
LocalVariableTable:
Start Length Slot Name Signature
0 19 0 this LA;
0 19 1 a I
0 19 2 b Ljava/lang/String;
0 19 3 c Ljava/lang/String;
0 19 4 d I
Quindi non v'è alcun uso di c
e d
nel costruttore o in pari.
Si può ancora fare secondo elenco ARG params utile anteponendo val
:
scala> case class B(a: Int, b: String)(val c: String, val d: Int)
defined class B
scala> val b = B(1, "two")("three", 4)
b: B = B(1,two)
scala> b.c
res6: String = three
scala> b.d
res8: Int = 4
Vediamo come l'uguaglianza e la hashcode funziona in questo caso:
scala> val b2 = B(1, "two")("no the same", 555)
b2: B = B(1,two)
scala> b == b2
res10: Boolean = true
scala> b.hashCode
res13: Int = -1563217100
scala> b2.hashCode
res14: Int = -1563217100
sembra funzionare nel modo che lo voglio, che personalmente non mi piace;)
Per completezza, la corrispondenza di modello predefinita è ancora come era per la classe A
:
scala> B.unapply _
res15: B => Option[(Int, String)] = <function1>
Specifiche linguaggio Scala spiega come funziona here.
I parametri formali nella prima sezione di parametro di una classe di caso sono denominati elementi; sono trattati appositamente. Innanzitutto, il valore di come parametro può essere estratto come campo di un modello di costruzione. In secondo luogo, un prefisso val è implicitamente aggiunto a tale parametro, a meno che il parametro abbia già un modificatore val o var. Quindi, viene generata una definizione di accesso per il parametro.
e
Ogni classe caso ignora implicitamente alcune definizioni dei metodi della classe scala.AnyRef a meno che una definizione dello stesso metodo è già dato nel caso classe stessa o di una definizione concreta della stessa il metodo viene fornito in alcune classi base della classe case diverse da AnyRef. In particolare:
- Metodo uguale: (Qualunque) Booleana è uguaglianza strutturale, in cui due istanze sono uguali se entrambi appartengono alla classe caso in questione e hanno uguali (rispetto al eguali) costruttore argomenti (limitato agli elementi della classe, ovvero il primo parametro sezione).
- Metodo hashCode: Int calcola un codice hash. Se i metodi hashCode dei membri della struttura dati corrispondono a valori uguali (rispetto ai valori uguali) a hash-code uguali, il metodo hashCode della classe case include anche .
- Metodo toString: String restituisce una rappresentazione stringa che contiene il nome della classe e dei suoi elementi.
Perché vuoi che si tratti di una case class? Le classi di casi hanno alcune caratteristiche di convenienza, ma il recupero dell'investimento è una perdita di flessibilità. Basta definire la propria classe e sovrascrivere equamente/hashCode da soli. –
Sì, capisco, ma eseguo alcuni pattern di corrispondenza pesante su questa classe di case, quindi devo lasciarlo come caso class! – sparkr
Forse vuoi rinominare la tua domanda in modo simile a "Elenchi di parametri multipli di Classe Case Scala" invece di Tupled –