2015-01-31 15 views
6

Quando normalmente utilizza un for-in-loop, il contatore (in questo caso number) è una costante in ogni iterazione:contatore come variabile a-in-loop

for number in 1...10 { 
    // do something 
} 

Questo significa che non posso cambiare number nel loop:

for number in 1...10 { 
    if number == 5 { 
     ++number 
    } 
} 

// doesn't compile, since the prefix operator '++' can't be performed on the constant 'number' 

c'è un modo per dichiarare number come variabile, senza dichiararlo prima del ciclo, o utilizzando un normale ciclo for (con l'inizializzazione, condizione e incremento)?

+1

Modifica del l'iteratore di un 'for' è solitamente considerato un codice errato. 'for in' non ha iteratore,' number' non è un iteratore. Il suo valore non influenza il loop in alcun modo. – Sulthan

risposta

12

Per comprendere il motivo per cui i non può essere disattivato, è necessario sapere cosa è lo for…in abbreviazione. for i in 0..<10 è espanso dal compilatore per il seguente:

var g = (0..<10).generate() 
while let i = g.next() { 
    // use i 
} 

Ogni volta che tutto il ciclo, i è una variabile appena dichiarata, il valore di scartare il risultato successivo di chiamare next sul generatore.

Ora, che whilepuò essere scritto in questo modo:

while var i = g.next() { 
    // here you _can_ increment i: 
    if i == 5 { ++i } 
} 

ma, naturalmente, non servirebbe - g.next() è ancora in corso per generare un 5 prossima volta intorno al ciclo. L'incremento nel corpo era inutile.

Presumibilmente per questo motivo, for…in non supporta la stessa sintassi var per la dichiarazione del suo contatore di loop - sarebbe molto confuso se non ti rendessi conto di come ha funzionato.

(a differenza di where, dove è possibile vedere cosa sta succedendo, la funzionalità var è occasionalmente utile, analogamente a quanto può essere func f(var i)).

Se quello che vuoi è di saltare alcuni iterazioni del ciclo, la cosa migliore (senza ricorrere a C-style for o while) è quello di utilizzare un generatore che salta i valori rilevanti:

// iterate over every other integer 
for i in 0.stride(to: 10, by: 2) { print(i) } 

// skip a specific number 
for i in (0..<10).filter({ $0 != 5 }) { print(i) } 

let a = ["one","two","three","four"] 

// ok so this one’s a bit convoluted... 
let everyOther = a.enumerate().filter { $0.0 % 2 == 0 }.map { $0.1 }.lazy 

for s in everyOther { 
    print(s) 
} 
+0

Dai semplicemente grandi risposte! –

+0

Swift 3 consente var per for ... in loop. Tuttavia, viene sovrascritto ad ogni turno. – Etan

2

La risposta è "no" e questa è una buona cosa. In caso contrario, un comportamento grossolanamente confuso come questo sarebbe possibile:

for number in 1...10 { 
    if number == 5 { 
     // This does not work 
     number = 5000 
    } 
    println(number) 
} 

Immaginate la confusione di qualcuno guardando il numero 5000 nella produzione di un ciclo che si suppone sia legato a una serie di 1 se 10, compreso.

Inoltre, cosa sceglierebbe Swift come valore successivo di 5000? Dovrebbe fermarsi? Dovrebbe continuare con il prossimo numero nell'intervallo prima dell'assegnazione? Dovrebbe generare un'eccezione sull'assegnazione fuori range? Tutte e tre le scelte hanno una certa validità per loro, quindi non c'è un chiaro vincitore.

Per evitare situazioni del genere, i progettisti di Swift hanno reso immutabili le variabili di loop nei loop di gamma.

+0

È molto utile pensare a 'for in 'come una struttura completamente diversa da un ciclo' for' comune. 'number' non è un iteratore, è un parametro di una funzione/blocco chiamato in ogni iterazione. – Sulthan