Per prima cosa, definirò sicuramente la prima versione come un ciclo for:
for (List<String> currentStrings = getCurrentStrings();
currentStrings.size() > 0; // if your List has an isEmpty() prefer it
currentStrings = getCurrentStrings()) {
...
}
Sfortunatamente non c'è un modo idiomatico in C ++, Java o C # che io conosca per eliminare la duplicazione tra inizializzatore e incrementatore. Personalmente mi piace astrarre il pattern di loop in Iterable
o Enumerable
o qualunque sia la tua lingua. Ma alla fine, questo sposta semplicemente la duplicazione in un posto riutilizzabile. Ecco un esempio in C #:
IEnumerable<T> ValidResults<T>(Func<T> grab, Func<bool, T> validate) {
for (T t = grab(); validate(t); t = grab()) {
yield return t;
}
}
// != null is a common condition
IEnumerable<T> NonNullResults<T>(Func<T> grab) where T : class {
return ValidResults(grab, t => t != null);
}
Ora puoi fare questo:
foreach(var currentStrings in NonNullResults(getCurrentStrings)) {
...
}
Il
% di% di C # co_de rende la scrittura facile; è più brutto in Java o C ++.
La cultura C ++ accetta più l'assegnazione-in-condition rispetto agli altri linguaggi e le conversioni booleane implicite sono effettivamente utilizzate in alcuni idiomi, ad es. digita le query:
if (Derived* d = dynamic_cast<Derived*>(base)) {...}
Quanto sopra si basa sulla conversione implicita di puntatori a bool ed è idiomatico. Eccone un altro:
std::string s;
while (std::getline(std::cin, s)) {...}
Questo modifica all'interno della condizione.
Il modello comune, tuttavia, è che la condizione stessa è banale, di solito si basa completamente su alcune conversioni implicite in bool. Dal momento che le raccolte non lo fanno, mettendo un test vuoto ci sarebbe da considerare meno idiomatico.
C culture è ancora più accettabile, con l'idioma del ciclo yield
simile a questo:
int c;
while((c = fgetc(stream)) != EOF) {...}
Ma nei linguaggi di livello superiore, questo è disapprovato, perché con il livello più alto di solito viene meno l'accettazione del codice difficile.