Στη Go, μπορείς να κάνεις επανάληψη πάνω σε ένα slice χρησιμοποιώντας το for και μια θέση, ή μπορείς να χρησιμοποιήσεις το range.
Το range σου επιτρέπει επίσης να κάνεις επανάληψη πάνω σε ένα map.
Κάθε επανάληψη επιστρέφει δύο τιμές: τη θέση/κλειδί και ένα αντίγραφο του στοιχείου σε αυτή τη θέση/κλειδί.
Πανεύκολο: η επανάληψη σε ένα slice γίνεται με τη σειρά που περιμένεις.
xi := []int{10, 20, 30}
for i, x := range xi {
fmt.Println(i, x)
}
// outputs:
// 0, 10
// 1, 20
// 2, 30
Η επανάληψη σε ένα map δημιουργεί ένα νέο πρόβλημα. Η σειρά τώρα είναι τυχαία.
hash := map[int]int{9: 10, 99: 20, 999: 30}
for k, v := range hash {
fmt.Println(k, v)
}
// outputs, for example:
// 99 20
// 999 30
// 9 10
Μπορεί να φαίνεται ότι η παραπάνω έξοδος είναι λανθασμένη, αφού κανείς θα περίμενε το πρώτο ζεύγος κλειδιού/τιμής στη δήλωση του map 9 10 να είναι το πρώτο που τυπώνεται και όχι το τελευταίο.
Ωστόσο, τα map δεν έχουν σειρά από τη φύση τους: δεν υπάρχει πρώτο ή τελευταίο ζεύγος κλειδιού/τιμής.
Γι' αυτό, όταν κάνεις επανάληψη στις καταχωρήσεις ενός map, η σειρά με την οποία θα επισκεφθούν οι καταχωρήσεις είναι τυχαία και δεν ακολουθεί κάποιο συγκεκριμένο μοτίβο.
Αυτό σημαίνει ότι η παραπάνω έξοδος είναι πιθανή, αλλά μπορεί να διαφέρει από αυτό που θα πάρεις αν δοκιμάσεις να το τρέξεις μόνος σου.
Για να μάθεις περισσότερα γι' αυτό, δες Προδιαγραφή της γλώσσας Go: ρήτρα range.
Στη Go, μια μεταβλητή που δεν χρησιμοποιείται θα πετάξει σφάλμα κατά τη μεταγλώττιση. Κάποιες φορές χρειάζεσαι μόνο την τιμή, όπως στο πρώτο παράδειγμα:
xi := []int{10, 20, 30}
for i, x := range xi {
fmt.Println(x)
}
// Go build failed: i declared but not used
Μπορείς να αντικαταστήσεις το i με _, που λέει στον μεταγλωττιστή ότι δεν χρησιμοποιούμε αυτή την τιμή:
xi := []int{10, 20, 30}
for _, x := range xi {
fmt.Println(x)
}
// outputs:
// 10
// 20
// 30
Αν θέλεις να τυπώσεις μόνο τη θέση, μπορείς να αντικαταστήσεις το x με _,
ή απλώς να παραλείψεις τη δήλωση:
xi := []int{10, 20, 30}
// for i, _ := range xi {
for i := range xi {
fmt.Println(i)
}
// outputs:
// 0
// 1
// 2
Ο ορισμός τύπου δημιουργεί έναν νέο επώνυμο τύπο, διακριτό από κάθε άλλον τύπο, ακόμη και από έναν με τον ίδιο υποκείμενο τύπο.
type File []bool
Εδώ το File αναφέρεται σε μία μόνο κάθετη στήλη μιας σκακιέρας, που συνήθως χαρακτηρίζεται με γράμματα από το A έως το H.
Κάθε τετράγωνο αυτής της στήλης αναπαρίσταται από μια τιμή Boolean (λογική τιμή) που δείχνει αν είναι κατειλημμένο ή όχι.
Τώρα που το File έχει οριστεί, μπορούμε να το χρησιμοποιήσουμε μέσα σε άλλους ορισμούς:
type Chessboard map[string]File
board := Chessboard{
"A": File{true, false, true},
"B": File{false, true, false},
}
Το Chessboard αντιστοιχίζει αναγνωριστικά στηλών σε τιμές File.
Κάθε File είναι ένα slice από Boolean που αναπαριστά τα τετράγωνα μιας στήλης της σκακιέρας.
Χωρίς αυτούς τους ορισμούς τύπων, το board θα ήταν ένα map[string][]bool, που θα έκανε πιο δύσκολο να καταλάβεις τι αναπαριστούμε.
Ως λάτρης του σκακιού, θα ήθελες να γράψεις τη δική σου εκδοχή του παιχνιδιού. Ναι, μπορεί να υπάρχουν ήδη πολλές υλοποιήσεις του σκακιού διαθέσιμες στο διαδίκτυο, αλλά η δική σου θα είναι μοναδική!
Κάθε τετράγωνο της σκακιέρας προσδιορίζεται από ένα ζεύγος γράμματος και αριθμού:
A B C D E F G H
8 # _ _ _ # _ _ # 8
7 _ _ _ _ _ _ _ _ 7
6 _ _ _ _ # _ _ # 6
5 _ # _ _ _ _ _ # 5
4 _ _ _ _ _ _ # # 4
3 # _ # _ _ _ _ # 3
2 _ _ _ _ _ _ _ # 2
1 # _ _ _ _ _ _ # 1
A B C D E F G H
Υλοποίησε τη συνάρτηση CountInFile(board Chessboard, file string) int.
Θα πρέπει να μετράει τον συνολικό αριθμό των κατειλημμένων τετραγώνων διατρέχοντας ένα map.
Επίστρεψε έναν ακέραιο.
Επίστρεψε πλήθος μηδέν (0) αν το file που δόθηκε δεν βρίσκεται στο map.
CountInFile(board, "A")
// => 3
Υλοποίησε τη συνάρτηση CountInRank(board Chessboard, rank int) int.
Θα πρέπει να μετράει τον συνολικό αριθμό των κατειλημμένων τετραγώνων διατρέχοντας το rank που δόθηκε.
Επίστρεψε έναν ακέραιο.
Επίστρεψε πλήθος μηδέν (0) αν το rank που δόθηκε δεν είναι έγκυρο (όχι μεταξύ 1 και 8, συμπεριλαμβανομένων).
CountInRank(board, 2)
// => 1
Υλοποίησε τη συνάρτηση CountAll(board Chessboard) int.
Θα πρέπει να μετράει πόσα τετράγωνα υπάρχουν στη σκακιέρα και να επιστρέφει έναν ακέραιο.
Εφόσον δεν χρειάζεται να ελέγξεις το περιεχόμενο των τετραγώνων, σκέψου να χρησιμοποιήσεις range παραλείποντας και το index και το value.
CountAll(board)
// => 64
Υλοποίησε τη συνάρτηση CountOccupied(board Chessboard) int.
Θα πρέπει να μετράει πόσα τετράγωνα είναι κατειλημμένα στη σκακιέρα.
Επίστρεψε έναν ακέραιο.
CountOccupied(board)
// => 15
Γράψου στο Exercism για να μάθεις και να κατακτήσεις Go με 34 έννοιες166 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.