2010-10-31 8 views
6

Mi imbatto in un problema standard come principiante di Scala: come posso definire due classi in modo tale che io possa creare un'istanza di una che sia l'altra come variabile membro, che a sua volta punta alla prima istanza ?riferimenti di classe avanti in Scala?

Vorrei finire con un'istanza di gioco che ha un membro di tipo Dealer che ha un membro del tipo di gioco, che è in realtà l'istanza gioco originale

Quindi, in questo caso, ogni istanza (Gioco, Rivenditore) ha un membro che è l'altra istanza. Qualcuno mi può guidare nel modo giusto per questo?

risposta

2

Penso che tu stia parlando di una dipendenza "bidirezionale", e questo è facile da fare se max una delle entità è immutabile (se vuoi che entrambi siano immutabili dovresti vedere la soluzione Moviz).

Nel mio esempio ho lasciato che l'Game fosse l'entità immutabile. Un rivenditore potrebbe non essere coinvolto in un gioco.

class Dealer(val name: String){ 
    var game: Option[Game] = None 
} 

case class Game(name: String, dealer: Dealer) 

// Instanciate the game and the dealer 
val olle = new Dealer("Olle") 
val ollesGame = Game("Olles Game", olle) 
olle.game = Some(ollesGame) 
+0

È possibile utilizzare valori pigri e blocchi, come mostrato da Moritz. – Landei

+0

@ Landei Grazie. Il testo è ora aggiornato. –

3

Hai due scelte qui:

  1. Fai i tuoi oggetti mutabili, poi basta usare esattamente le stesse tecniche come si farebbe in Java.
  2. Renderli immutabili, quindi rinunciare alle dipendenze bidirezionali.

Per capire perché, considerare la seguente trasformazione tra alberi (immutabili). Questi sono entrambi definiti con ogni nodo genitore in possesso di un elenco di nodi figlio, ma bambini non sanno i genitori:

a    (a) 
    b    (b) 
    c    c 
    d  -->  (d) 
    e    e 
    f    f 
    g    g 

In particolare, il nodo d è stato clonato con il nuovo valore. Per fare questo, abbiamo anche dovuto clonare tutti i nodi genitore (mostrati tra parentesi).

Se i nodi hanno tenuto il loro genitore, quindi c avrebbe dovuto essere "aggiornato" per riflettere il nuovo b nodo e e, f, g avrebbe dovuto essere aggiornato per riflettere il nuovo a nodo. Ad esempio, l'intero albero dovrebbe essere copiato!

Solo mantenendo le relazioni in una direzione, da padre a figlio, diventa possibile riutilizzare c, e, f, g attraverso le versioni successive della struttura. Questa è una potente ottimizzazione ed è la chiave per scrivere algoritmi funzionali efficienti.

8

Se avete veramente bisogno di fare le classi immutabili l'unica opzione è quella di utilizzare dai parametri di nomi nel costruttore e creare sempre casi come pigri val s:

class Dealer(val name: String, g: => Game) { 
    lazy val game = g 
    override def toString = "Dealer(name=%s, game=%s)".format(name, game.name) 
} 

class Game(val name: String, d: => Dealer) { 
    lazy val dealer = d 
    override def toString = "Game(name=%s, dealer=%s)".format(name, dealer.name) 
} 

lazy val game: Game = new Game("Doppelkopf", new Dealer("Peter", game)) 
lazy val dealer: Dealer = new Dealer("Tina", new Game("Poker", dealer)) 

notare che è necessario il tipo di attribuzione sul lazy vals o non verrà compilato.

+0

@Moriz Whoa! Ecco alcune linee di fantasia. Ciò dimostra che tutto è possibile in Scala. –

+0

Quanto sopra non viene compilato per me. –

+0

: 5: Errore: non trovato: Tipo di gioco Dealer classe (nome val: String, g: => Gioco) { ^ : 5: Errore: non trovato: Tipo di Dealer classe Game (nome val: String , d: => Commerciante) { ^ –

Problemi correlati