Στη Go, ένα struct είναι μια ακολουθία από ονομασμένα στοιχεία που ονομάζονται πεδία, κάθε πεδίο έχει ένα όνομα και έναν τύπο.
Το όνομα ενός πεδίου πρέπει να είναι μοναδικό μέσα στο struct.
Τα struct μπορούν να συγκριθούν με τις κλάσεις στο παράδειγμα του αντικειμενοστρεφούς προγραμματισμού.
struct
Δημιουργείς ένα νέο struct χρησιμοποιώντας τις λέξεις-κλειδιά type και struct και ορίζεις ρητά το όνομα και τον τύπο των πεδίων.
Για παράδειγμα, εδώ ορίζουμε το struct Shape, που κρατά το όνομα ενός σχήματος και το μέγεθός του:
type Shape struct {
name string
size int
}
Τα ονόματα πεδίων στα struct ακολουθούν τη σύμβαση της Go: τα πεδία των οποίων το όνομα ξεκινά με πεζό γράμμα είναι ορατά μόνο σε κώδικα του ίδιου πακέτου, ενώ εκείνα των οποίων το όνομα ξεκινά με κεφαλαίο γράμμα είναι ορατά και σε άλλα πακέτα.
struct
Αφού ορίσεις το struct, χρειάζεται να δημιουργήσεις ένα νέο στιγμιότυπο ορίζοντας τα πεδία χρησιμοποιώντας το όνομά τους, με οποιαδήποτε σειρά:
s := Shape {
name: "Square",
size: 25,
}
Για να διαβάσεις ή να τροποποιήσεις τα πεδία ενός στιγμιότυπου, χρησιμοποίησε τον συμβολισμό .:
// Update the name and the size
s.name = "Circle"
s.size = 35
fmt.Printf("name: %s size: %d\n", s.name, s.size)
// Output: name: Circle size: 35
Τα πεδία στα οποία δεν έχει εκχωρηθεί αρχική τιμή, θα έχουν τη μηδενική τους τιμή. Για παράδειγμα:
s := Shape{name: "Circle"}
fmt.Printf("name: %s size: %d\n", s.name, s.size)
// Output: name: Circle size: 0
Μπορείς να δημιουργήσεις ένα στιγμιότυπο ενός struct χωρίς να χρησιμοποιήσεις τα ονόματα των πεδίων, αρκεί να ορίσεις τα πεδία με τη σειρά:
s := Shape {
"Oval",
20,
}
Ωστόσο, αυτή η σύνταξη θεωρείται εύθραυστος κώδικας, καθώς μπορεί να σπάσει όταν προστεθεί ένα πεδίο, ειδικά όταν το νέο πεδίο είναι διαφορετικού τύπου.
Στο παρακάτω παράδειγμα προσθέτουμε ένα επιπλέον πεδίο στο Shape:
type Shape struct {
name string
description string // new field 'description' added
size int
}
s := Shape{
"Circle",
20,
}
// Since the second field of the struct is now a string and not an int,
// the compiler will throw an error when compiling the program:
// Output: cannot use 20 (type untyped int) as type string in field value
// Output: too few values in Shape{...}
Μερικές φορές είναι ωραίο να έχεις συναρτήσεις που μας βοηθούν να δημιουργούμε στιγμιότυπα struct.
Κατά σύμβαση, αυτές οι συναρτήσεις συνήθως ονομάζονται New ή τα ονόματά τους ξεκινούν με New, αλλά επειδή είναι απλώς κανονικές συναρτήσεις, μπορείς να τους δώσεις όποιο όνομα θέλεις.
Μπορεί να σου θυμίζουν κατασκευαστές σε άλλες γλώσσες, αλλά στη Go είναι απλώς κανονικές συναρτήσεις.
Στο παρακάτω παράδειγμα, μία από αυτές τις συναρτήσεις New χρησιμοποιείται για να δημιουργήσει ένα νέο στιγμιότυπο του Shape και να ορίσει αυτόματα μια προεπιλεγμένη τιμή για το size του σχήματος:
func NewShape(name string) Shape {
return Shape{
name: name,
size: 100, //default-value for size is 100
}
}
NewShape("Triangle")
// => Shape { name: "Triangle", size: 100 }
Η χρήση συναρτήσεων New μπορεί να έχει τα εξής πλεονεκτήματα:
New συχνά δηλώνονται στο ίδιο πακέτο με τα struct που αρχικοποιούν, μπορούν να αρχικοποιήσουν ακόμη και ιδιωτικά πεδία του struct
Σε αυτή την άσκηση θα οργανώσεις αγώνες ανάμεσα σε διάφορα είδη τηλεκατευθυνόμενων αυτοκινήτων. Κάθε αυτοκίνητο έχει τη δική του ταχύτητα και τα δικά του χαρακτηριστικά κατανάλωσης μπαταρίας.
Τα αυτοκίνητα ξεκινούν με πλήρως φορτισμένες (100%) μπαταρίες. Κάθε φορά που οδηγείς το αυτοκίνητο με το τηλεχειριστήριο, αυτό διανύει τόσα μέτρα όση είναι η ταχύτητά του και μειώνει το ποσοστό της υπόλοιπης μπαταρίας κατά την κατανάλωση μπαταρίας του.
Αν η μπαταρία ενός αυτοκινήτου είναι κάτω από το ποσοστό κατανάλωσης μπαταρίας του, δεν μπορείς να οδηγήσεις άλλο το αυτοκίνητο.
Κάθε πίστα αγώνων έχει τη δική της απόσταση. Τα αυτοκίνητα δοκιμάζονται ελέγχοντας αν μπορούν να τερματίσουν την πίστα χωρίς να ξεμείνουν από μπαταρία.
Όρισε ένα struct Car με τα ακόλουθα πεδία τύπου int:
Επίτρεψε τη δημιουργία ενός τηλεκατευθυνόμενου αυτοκινήτου ορίζοντας μια συνάρτηση NewCar που δέχεται την ταχύτητα του αυτοκινήτου σε μέτρα
και το ποσοστό κατανάλωσης μπαταρίας ως τις δύο παραμέτρους της (και οι δύο τύπου int) και επιστρέφει ένα στιγμιότυπο Car:
speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
// => Car{speed: 5, batteryDrain: 2, battery:100, distance: 0}
Όρισε έναν ακόμη τύπο struct με το όνομα Track και το πεδίο distance ακέραιου τύπου.
Επίτρεψε τη δημιουργία μιας πίστας αγώνων ορίζοντας μια συνάρτηση NewTrack που δέχεται την απόσταση της πίστας σε μέτρα ως τη μοναδική της παράμετρο (τύπου int):
distance := 800
track := NewTrack(distance)
// => Track{distance: 800}
Υλοποίησε τη συνάρτηση Drive που ενημερώνει τον αριθμό των μέτρων που διανύθηκαν με βάση την ταχύτητα του αυτοκινήτου και μειώνει τη μπαταρία σύμφωνα με την κατανάλωση μπαταρίας.
Αν δεν υπάρχει αρκετή μπαταρία για άλλη μια οδήγηση, το αυτοκίνητο δεν θα κινηθεί:
speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
car = Drive(car)
// => Car{speed: 5, batteryDrain: 2, battery: 98, distance: 5}
Για να τερματίσει έναν αγώνα, ένα αυτοκίνητο πρέπει να μπορεί να διανύσει την απόσταση του αγώνα.
Αυτό σημαίνει να μην εξαντλήσει τη μπαταρία του πριν περάσει τη γραμμή τερματισμού.
Υλοποίησε τη συνάρτηση CanFinish που δέχεται ένα στιγμιότυπο Car και ένα στιγμιότυπο Track ως παράμετρο και επιστρέφει true αν το αυτοκίνητο μπορεί να τερματίσει τον αγώνα. Διαφορετικά, επιστρέφει false.
Υπόθεσε ότι βρίσκεσαι αυτή τη στιγμή στη γραμμή εκκίνησης του αγώνα και βάζεις μπροστά τη μηχανή του αυτοκινήτου για τον αγώνα. Λάβε υπόψη ότι η μπαταρία του αυτοκινήτου μπορεί να μην είναι απαραίτητα πλήρως φορτισμένη όταν ξεκινάει ο αγώνας:
speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
distance := 100
track := NewTrack(distance)
CanFinish(car, track)
// => true
Γράψου στο Exercism για να μάθεις και να κατακτήσεις Go με 34 έννοιες165 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.