Uso dell'istruzione condizionale loop for non correlata alla variabile iterating

2

È considerata una forma decente scrivere un codice come questo:

int done = 0;
for (x = 0; !done; x++) {

    ... something involving 'x', that might end early ...

    if (!(x < max))
        done = 1;
}

al contrario di dover utilizzare un ciclo while :

int done;
x = 0;
while (!done) {

    ... something involving 'x', that might end early ...

    if (!(x < max))
        done = 1;
    x++;
}

o dover break di un ciclo for :

for (x = 0; x < max; x++) {
    int done;

    ... something involving 'x', that might end early ...

    if (done)
        break;
}

Preferisco il primo, principalmente perché non mi piace break di out di loop, preferisco for loops e sembra ancora pulito. Il secondo mi sembra quello che gli altri probabilmente utilizzerebbero.

Il terzo mi sembra icky, ma sembrava qualcosa d'altro che altri potrebbero usare in opposizione al primo.

Quali sono i vantaggi dell'utilizzo di uno sull'altro? Dovrebbero essere usati ciascuno in momenti diversi, è generalmente corretto, o si tratta solo di preferenze personali?

    
posta haneefmubarak 16.12.2014 - 08:50
fonte

3 risposte

1

Considera quanto segue:

int done = 0;
for (i = 0; !done && i < max; ++i) {
    // ... something involving 'i', that might end early ...
}

La mia preferenza personale qui è di mantenere la "condizione di rottura" in un punto. Se si aggiunge una seconda clausola if che si interrompe, si rischia di saltare questa logica quando in un secondo momento l'utente o un altro programmatore lo leggeranno. Come regola generale, dovresti evitare di usare interruzioni nei loop a meno che non sia inevitabile. In un certo senso, è l'equivalente di un goto.

In questo modo il numero di linee è ridotto al minimo e, oserei dire, il codice sembra più pulito in questo modo. Nota che ho usato "i" al posto di "x" perché se si tratta di un indice, di solito, preferisco io, anche se puoi usare quello che preferisci.

In generale, se devo scorrere un elenco o una serie di elementi, userò un ciclo for, anche se, come nel tuo caso, potresti avere delle regole condizionali per uscire dal ciclo. Userò un ciclo while se sto iterando attraverso un elenco o una serie di elementi e l'indice / posizione nell'elenco o l'array non è importante. Userò anche se non ci sarà una fine prestabilita al ciclo. Ciò non significa che non ce ne sia uno, ma piuttosto che non so quando il ciclo while finirà prima di iniziare.

In genere eviterò di farlo ... mentre il più delle volte, la ragione per cui non puoi continuare a causa della tua condizione di interruzione dipende da cosa dipenderà la logica contenuta all'interno, e di solito finirai con qualcosa del tipo:

condition = 0;
do {
    if(!condition) {
       // Perform some operation and possibly set condition to 1.
    }
} while (!condition);

Tendo a quel punto a rompere l'operazione in una sua funzione:

while(performOperation()) ;

...

int performOperation() {
    // Set result to value indicating success or failure
    return result;  
}

Spero che ti aiuti!

    
risposta data 16.12.2014 - 09:40
fonte
4

Diversi blocchi hanno significati diversi: usando quelli che sono comunemente usati per uno scopo specifico, rendi il tuo codice più facile da leggere e mantenere. Usando quelli che non sono comunemente usati per lo scopo, costringi i lettori del tuo codice a fermarsi e pensa perché hai usato questo costrutto invece di quello usato comunemente .

Pur essendo semanticamente corretto, for (x = 0; !done; x++) non è qualcosa di normale. while o do...while vengono utilizzati in situazioni in cui è necessario interrompere un ciclo quando viene soddisfatta una condizione:

x = 0;
do {
    ... something involving 'x', that might end early.
    x++;
}
while (x <= max)

(assumendo che max possa cambiare all'interno del ciclo, altrimenti puoi semplicemente fare for (x = 0; x <= max; x++) )

Anche conciso è importante. Meno codice significa meno rischi di errori. Ad esempio, il tuo codice while -based è inutilmente complicato. Ad esempio, (!(x < max)) richiede tempo per comprendere e può essere fonte di errore. Il blocco if all'interno di while aggiunge anche la complessità. Inoltre, aggiungi una variabile che trascende il blocco while e che può essere semplicemente rimossa.

I prefer the first one, mainly because I dislike breaking out of loops

Questa è la tua opinione personale che è preziosa quando stai lavorando a un progetto personale che non sarà mai condiviso con nessuno. Non appena pensi che il codice possa essere open source (e in realtà letto e usato da altri) o il tuo lavoro in una squadra, ciò che preferisci potrebbe andare contro:

  • Le tue abitudini di squadra. Se in una squadra di 6 persone, 5 stanno usando un costrutto e stai usando un costrutto diverso, per usare la coerenza, usa quello che usano i tuoi compagni di squadra, anche se il tuo sembra chiaramente superiore (a meno che, naturalmente, non sia possibile convincere i tuoi compagni di squadra) all'inizio del progetto che la tua è migliore)

  • Usi della community. Diverse comunità usano stili diversi, il che porta a discrepanze tra le lingue. Ad esempio:

    if (something) {
    }
    

    in JavaScript dovrebbe essere scritto:

    if (something)
    {
    }
    

    in C #. Attenersi agli usi della community rende più facile per le persone esterne al tuo progetto leggere il tuo codice (ad esempio se pubblichi un pezzo di codice su Stack Overflow) o per leggere codice da altri progetti.

  • Controlli stile e stile ufficiali. Potresti non essere d'accordo con la scelta degli autori della guida di stile, ma il fatto è che la coerenza è più importante.

    Ad esempio, trovo che alcune regole della PSR-2 siano piuttosto strane. Ad esempio:

    function hello()
    {                      // Newline here.
        if (something) {   // No newline here.
        }
    }
    

    Tuttavia, preferisco usare questo stile piuttosto che crearne di miei e trovarmi incoerente con migliaia di programmatori PHP.

risposta data 16.12.2014 - 09:05
fonte
0

Il primo modulo

for ( x = 0; !done; x++ )

è un IMO strano e non intuitivo. Non c'è una correlazione evidente tra x e done in questo contesto (devi rivedere il corpo del ciclo per vedere che done è impostato quando x non è più inferiore a max )

In tal caso, preferirei vedere qualcosa di simile

for ( x = 0; x < max; x++ )  

Tuttavia, sei preoccupato che il ciclo termini prima che x sia uguale a max a causa di qualche altra condizione. Se vuoi terminare il ciclo non appena l'altra condizione è vera, puoi fare qualcosa di simile al seguente:

for ( x = 0; x < max && !other_exit_condition; x++ )
{
  // do the thing with x that may set other_exit_condition
  if ( other_exit_condition )
    continue; 
  else
  {
    // rest of loop body
  }
}

L'istruzione continue risale all'inizio del ciclo, che quindi termina perché other_exit_condition è ora true. Ma in realtà non è meglio che usare un break , onestamente.

    
risposta data 16.12.2014 - 21:21
fonte

Leggi altre domande sui tag