Οι δομές είναι μια επέκταση χτισμένη πάνω στα maps, η οποία παρέχει ελέγχους κατά τη μεταγλώττιση και προεπιλεγμένες τιμές. Μια δομή παίρνει το όνομά της από το module στο οποίο ορίζεται. Για να ορίσεις μια δομή, χρησιμοποίησε την κατασκευή defstruct. Η κατασκευή συνήθως ακολουθεί αμέσως μετά τον ορισμό του module. Το defstruct δέχεται είτε μια λίστα από atoms (για προεπιλεγμένες τιμές nil) είτε μια λίστα με λέξεις-κλειδιά (για συγκεκριμένες προεπιλεγμένες τιμές). Τα πεδία χωρίς προεπιλεγμένες τιμές πρέπει να προηγούνται των πεδίων με προεπιλεγμένες τιμές.
defmodule Plane do
defstruct [:engine, wings: 2]
end
plane = %Plane{}
# => %Plane{engine: nil, wings: 2}
Επειδή οι δομές είναι χτισμένες πάνω στα maps, μπορούμε να χρησιμοποιήσουμε τις περισσότερες συναρτήσεις των maps για να πάρουμε και να χειριστούμε τιμές. Το Access Behaviour δεν υλοποιείται για τις δομές. Αντιθέτως, προτείνεται να χρησιμοποιείς τον τελεστή στατικής πρόσβασης . για να έχεις πρόσβαση στα πεδία μιας δομής.
λήψη/ανάκτηση τιμών πεδίων:
plane = %Plane{}
plane.engine
# => nil
Map.fetch(plane, :wings)
# => {:ok, 2}
ενημέρωση τιμών πεδίων
plane = %Plane{}
%{plane | wings: 4}
# => %Plane{engine: nil, wings: 4}
Οι δομές μπορούν να χρησιμοποιηθούν στην αντιστοίχιση προτύπων με ή χωρίς το όνομα της δομής.
plane = %Plane{}
%Plane{wings: wings} = plane
%{wings: wings} = plane
Συμπεριλαμβάνοντας το όνομα της δομής στο πρότυπο, μπορείς να βεβαιωθείς ότι και οι δύο πλευρές, αριστερά και δεξιά, είναι δομές του ίδιου τύπου.
defmodule Helicopter do
defstruct [:engine, rotors: 1]
end
%Plane{} = %Helicopter{}
# => (MatchError) no match of right hand side value: %Helicopter{engine: nil, rotors: 1}
Μπορούμε να χρησιμοποιήσουμε το χαρακτηριστικό module @enforce_keys με μια λίστα από κλειδιά πεδίων, ώστε να διασφαλίσουμε ότι οι τιμές αρχικοποιούνται όταν δημιουργείται η δομή. Αν ένα κλειδί δεν περιλαμβάνεται στη λίστα, η τιμή του θα είναι nil, όπως φαίνεται στο παραπάνω παράδειγμα. Αν ένα υποχρεωτικό κλειδί δεν αρχικοποιηθεί, πετιέται ένα σφάλμα.
defmodule User do
@enforce_keys [:username]
defstruct [:username]
end
%User{}
# => (ArgumentError) the following keys must also be given when building struct User: [:username]
Σε αυτή την άσκηση θα παίξεις με ένα τηλεκατευθυνόμενο αυτοκίνητο, για το οποίο τελικά μάζεψες αρκετά χρήματα για να το αγοράσεις.
Τα αυτοκίνητα ξεκινούν με πλήρεις (100%) μπαταρίες. Κάθε φορά που οδηγείς το αυτοκίνητο με το τηλεχειριστήριο, διανύει 20 μέτρα και καταναλώνει ένα τοις εκατό της μπαταρίας. Το ψευδώνυμο του αυτοκινήτου δεν είναι γνωστό μέχρι να δημιουργηθεί.
Το τηλεκατευθυνόμενο αυτοκίνητο έχει μια εντυπωσιακή οθόνη LED που δείχνει δύο πληροφορίες:
"<METERS> meters"."Battery at <PERCENTAGE>%".Αν η μπαταρία είναι στο 0%, δεν μπορείς πια να οδηγήσεις το αυτοκίνητο και η ένδειξη της μπαταρίας θα δείχνει "Battery empty".
Υλοποίησε τη συνάρτηση RemoteControlCar.new/0 ώστε να επιστρέφει ένα ολοκαίνουργιο struct τηλεκατευθυνόμενου αυτοκινήτου:
RemoteControlCar.new()
# => %RemoteControlCar{
# battery_percentage: 100,
# distance_driven_in_meters: 0,
# nickname: "none"
# }
Το ψευδώνυμο απαιτείται από το struct. Βεβαιώσου ότι αρχικοποιείται μια τιμή στη συνάρτηση new, αλλά όχι στο struct.
Υλοποίησε τη συνάρτηση RemoteControlCar.new/1 ώστε να επιστρέφει ένα ολοκαίνουργιο struct τηλεκατευθυνόμενου αυτοκινήτου με ένα ψευδώνυμο που δίνεται:
RemoteControlCar.new("Blue")
# => %RemoteControlCar{
# battery_percentage: 100,
# distance_driven_in_meters: 0,
# nickname: "Blue"
# }
Υλοποίησε τη συνάρτηση RemoteControlCar.display_distance/1 ώστε να επιστρέφει την απόσταση όπως εμφανίζεται στην οθόνη LED:
car = RemoteControlCar.new()
RemoteControlCar.display_distance(car)
# => "0 meters"
Βεβαιώσου ότι η συνάρτηση δέχεται ως όρισμα μόνο ένα struct RemoteControlCar.
Υλοποίησε τη συνάρτηση RemoteControlCar.display_battery/1 ώστε να επιστρέφει το ποσοστό της μπαταρίας όπως εμφανίζεται στην οθόνη LED:
car = RemoteControlCar.new()
RemoteControlCar.display_battery(car)
# => "Battery at 100%"
Βεβαιώσου ότι η συνάρτηση δέχεται ως όρισμα μόνο ένα struct RemoteControlCar. Αν η μπαταρία είναι στο 0%, η ένδειξη της μπαταρίας θα δείχνει "Battery empty".
Υλοποίησε τη συνάρτηση RemoteControlCar.drive/1 που:
RemoteControlCar.new("Red")
|> RemoteControlCar.drive()
# => %RemoteControlCar{
# battery_percentage: 99,
# distance_driven_in_meters: 20,
# nickname: "Red"
# }
Βεβαιώσου ότι η συνάρτηση δέχεται ως όρισμα μόνο ένα struct RemoteControlCar.
Ενημέρωσε τη συνάρτηση RemoteControlCar.drive/1 ώστε να μην αυξάνει την απόσταση που διανύθηκε ούτε να μη μειώνει το ποσοστό της μπαταρίας όταν η μπαταρία έχει αποφορτιστεί (στο 0%):
%RemoteControlCar{
battery_percentage: 0,
distance_driven_in_meters: 1980,
nickname: "Red"
}
|> RemoteControlCar.drive()
# => %RemoteControlCar{
# battery_percentage: 0,
# distance_driven_in_meters: 1980,
# nickname: "Red"
# }
Γράψου στο Exercism για να μάθεις και να κατακτήσεις Elixir με 58 έννοιες168 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.