2016-03-27 31 views
5

Wygląda na to, że następująca pętla Swift for-in próbuje przejść przez więcej elementów niż w macierzy.Pętla wejścia w jedną stronę idzie zbyt daleko i znajduje "zero" podczas rozpakowywania.

Na przykład, ten kod:

var list:[Int?] = [1,2,3,4,5,6,7] 

print("C-Style for loop") 
for var i=0; i<list.count; i++ 
{ 
    var x:Int = list[i]! 
    print(x) 
} 

print("\nFor-in loop") 
for var x:Int! in list 
{ 
    print(x) 
} 

Pobiera tego wyjścia:

C-Style for loop 
1 
2 
3 
4 
5 
6 
7 

For each loop 
1 
2 
3 
4 
5 
6 
7 
fatal error: unexpectedly found nil while unwrapping an Optional value 
... 
Illegal instruction: 4 

I musi być brakuje czegoś tutaj. Czy nie powinna być liczbą elementów, które pętla for-in próbuje odwijać?

Na powyższym obrazku pętla wejścia działa zgodnie z oczekiwaniami, jeśli zamiast listy jest używana lista [Int] bez rozpakowywania.

Jestem na wersji Swift 2.1.1.

+0

niektóre dziwne zachowanie tutaj. Jeśli nazwiesz 'list' jako' [Int] ', a następnie oznaczysz' x' jako 'Int?', To 'for-in' wypisze' nil' na zawsze. – BallpointBen

+0

@Robert Takie zachowanie nie jest szczególnie dziwne, jeśli rozumiesz, jak to działa ... ale Swift prawdopodobnie po prostu zapobiegnie temu, aby 'x' oznaczało etykietę jako opcjonalną (ponieważ może tylko spowodować nieskończoną pętlę). – nhgrif

+0

Czy możesz krótko wyjaśnić, co się dzieje? Dlaczego tworzy to nieskończoną pętlę? – BallpointBen

Odpowiedz

4

Zasadniczo zrobiłeś coś, czego nie powinieneś robić, a więc natknąłeś się na coś, co prawdopodobnie jest błędem kompilatora (ponieważ kompilator Cię nie zatrzymał). Bardzo dobrze!

Teraz rozwiązanie. Najwyraźniej starasz się rozwinąć ze swoim Int!. Aby rozpakować bezpiecznie użyć for case składnię:

let list:[Int?] = [1,2,3,4,5,6,7] 
for case let x? in list 
{ 
    print(x) // 1, 2, 3, 4, 5, 6, 7 
} 

inną drogą (taki sam wynik):

let list:[Int?] = [1,2,3,4,5,6,7] 
list.flatMap{$0}.forEach{print($0)} // 1, 2, 3, 4, 5, 6, 7 
+0

Więc dla każdego cierpi ten sam problem ... przerażający. – Darko

+0

@Darko no it does not, actually; daje mi to inne rozwiązanie - proste 'list.forEach {print (0 $!)} 'działa (choć oczywiście jest to potencjalnie niebezpieczne z innych powodów) – matt

+0

Tak, ale również występuje błąd list.forEach {print ($ 0)}. Zapotrzebowanie na FlatMap jest dla mnie przerażające. – Darko

2

Wymuszone rozpakowanie, takie jak x:Int!, jest niebezpiecznym stylem kodowania, gdy nie można wykluczyć zera. To samo dotyczy var x:Int = list[i]!.

to działa:

print("\nFor-in loop") 
for x in list { 
    print(x) 
} 

Tutaj pozwalają x wynosi zero i można bezpiecznie sprawdzić zera później.

Teraz na pytanie, dlaczego przerwy kod:

Wewnętrznie Swift używa list.generate() dla dla w pętli. Generatory są zerowe, co jest prawdopodobnie powodem, dla którego twój kod się psuje.

+0

Ale problem polega na tym, że daje to opcjonalne (1), opcjonalne (2) itd., Które nie jest tym, co chce OP. – matt

+0

Masz rację. Podejrzewałem, że wydruk służy tylko do debugowania, a OP najwyraźniej wie, jak się rozwinąć. Bardziej interesującym dla mnie było pytanie, dlaczego się nie udaje. –