Domanda

Ho un algoritmo ricorsivo che scorre una stringa, carattere per carattere, e la analizza per creare una struttura ad albero.Voglio essere in grado di tenere traccia dell'indice dei caratteri in cui si trova attualmente il parser (per i messaggi di errore tanto quanto per qualsiasi altra cosa) ma non sono interessato a implementare qualcosa come una tupla per gestire più tipi restituiti.

Ho provato a utilizzare un tipo intero, dichiarato all'esterno del metodo e passato al metodo ricorsivo, ma poiché è finale, gli incrementi delle chiamate ricorsive vengono "dimenticati" al mio ritorno.(Perché l'incremento del valore intero rende il punto di riferimento dell'oggetto passato per valore su un nuovo oggetto)

C'è un modo per far funzionare qualcosa di simile che non inquini il mio codice?

È stato utile?

Soluzione

Dato che hai già scoperto l'hack degli interi pseudo-mutabili, che ne dici di questa opzione:

Ha senso per te creare una classe Parser separata?Se lo fai, puoi memorizzare lo stato corrente in una variabile membro.Probabilmente dovrai pensare a come gestire eventuali problemi di sicurezza del thread e potrebbe essere eccessivo per questa particolare applicazione, ma potrebbe funzionare per te.

Altri suggerimenti

È una specie di trucco, ma a volte utilizzo un AtomicInteger, che è modificabile, per fare cose del genere.Ho anche visto casi in cui viene passato un int[] di dimensione 1.

La soluzione attuale che sto utilizzando è:

int[] counter = {0};

e poi passarlo all'algoritmo ricorsivo:

public List<Thing> doIt (String aString, int[] counter) { ... }

e quando voglio incrementarlo:

counter[0]++;

Non molto elegante, ma funziona...

I numeri interi sono immutabili, il che significa che quando li passi come argomento crea una copia anziché un riferimento allo stesso elemento.(spiegazione).

Per ottenere il comportamento che stai cercando, puoi scrivere la tua classe che è come Integer solo mutabile.Quindi, basta passarlo alla funzione ricorsiva, viene incrementato all'interno della ricorsione e quando si accede nuovamente al termine della ricorsione manterrà comunque i suoi nuovi valori.

Modificare:Tieni presente che l'utilizzo di un array int[] è una variazione di questo metodo...In Java, anche gli array vengono passati per riferimento anziché copiati come primitive o classi immutabili.

Potresti semplicemente usare una variabile di classe int statica che viene incrementata ogni volta che viene chiamato il tuo metodo doIt.

Potresti anche fare:

private int recurse (int i) {

    if (someConditionkeepOnGoing) {
        i = recurse(i+1);
    }

    return i;
}

Ad essere sincero, ricodificherei la funzione per renderla un algoritmo lineare che utilizza un loop.In questo modo non hai alcuna possibilità di rimanere senza spazio heap se stai attraversando una stringa estremamente grande.Inoltre, non sarebbe necessario avere un parametro aggiuntivo solo per tenere traccia del conteggio.

Ciò probabilmente avrebbe anche il risultato di rendere l'algoritmo più veloce perché non è necessario effettuare una chiamata di funzione per ogni carattere.

A meno che, ovviamente, non vi sia una ragione specifica per cui debba essere ricorsivo.

Una possibilità che mi viene in mente è memorizzare il conteggio in una variabile membro della classe.Ciò ovviamente presuppone che il pubblico doIt il metodo viene chiamato solo da un singolo thread.

Un'altra opzione consiste nel rifattorizzare il metodo pubblico per chiamare un metodo di supporto privato.Il metodo privato accetta l'elenco come parametro e restituisce il conteggio.Per esempio:

public List<Thing> doIt(String aString) {
    List<Thing> list = new ArrayList<Thing>();
    int count = doItHelper(aString, list, 0);
    // ...
    return list;
}

private int doItHelper(String aString, List<Thing> list, int count) {
    // ...
    // do something that updates count
    count = doItHelper(aString, list, count);
    // ...
    return count;
}

Ciò presuppone che tu possa eseguire la gestione degli errori in pubblico doIt metodo, poiché il count la variabile non viene effettivamente restituita al chiamante.Se è necessario farlo, potresti ovviamente lanciare un'eccezione:

public List<Thing> doIt(String aString) throws SomeCustomException {
    List<Thing> list = new ArrayList<Thing>();
    int count = doItHelper(aString, list, 0);
    // ...
    if (someErrorOccurred) {
        throw new SomeCustomException("Error occurred at chracter index " + count, count);
    }
    return list;
}

È difficile sapere se ciò sarà d'aiuto senza sapere di più su come funziona effettivamente il tuo algoritmo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top