Μια πλειάδα είναι μια πεπερασμένη διατεταγμένη λίστα στοιχείων που είναι αμετάβλητη. Οι πλειάδες απαιτούν όλες οι θέσεις να έχουν σταθερό τύπο. Αυτό με τη σειρά του σημαίνει ότι ο μεταγλωττιστής γνωρίζει τι τύπος βρίσκεται σε κάθε θέση. Οι τύποι που χρησιμοποιούνται σε μια πλειάδα μπορούν να διαφέρουν σε κάθε θέση, αλλά οι τύποι πρέπει να είναι γνωστοί κατά τον χρόνο μεταγλώττισης.
Ανάλογα με το αν οι τύποι των τιμών της πλειάδας μπορούν να ερμηνευτούν κατά τη μεταγλώττιση, η πλειάδα μπορεί να δημιουργηθεί με διαφορετικούς τρόπους. Αν οι τιμές είναι γνωστές κατά τον χρόνο μεταγλώττισης, η πλειάδα μπορεί να δημιουργηθεί χρησιμοποιώντας τη σύνταξη της κυριολεκτικής πλειάδας, αλλιώς πρέπει να δηλωθούν ρητά. Είναι επίσης σημαντικό οι τύποι των τιμών να ταιριάζουν με τους τύπους που καθορίζονται στην πλειάδα και ο αριθμός των τιμών να ταιριάζει με τον αριθμό των τύπων που καθορίζονται. Ακολουθεί ένα παράδειγμα ορισμού μέσω της σύνταξης της κυριολεκτικής πλειάδας:
tuple = {1, "foo", 'c'} # Tuple(Int32, String, Char)
Υπάρχει επίσης η δυνατότητα να δημιουργήσεις μια πλειάδα χρησιμοποιώντας την κλάση Tuple.
tuple = Tuple(Int32, String, Char).new(1, "foo", 'c')
Εναλλακτικά, μπορείς να καθορίσεις ρητά τον τύπο της μεταβλητής που ανατίθεται στην πλειάδα.
tuple : Tuple(Int32, String, Char) = {1, "foo", 'c'}
Ο ρητός καθορισμός του τύπου της πλειάδας μπορεί να είναι χρήσιμος, καθώς επιτρέπει να οριστεί ότι μια θέση πρέπει να περιέχει τύπο ένωσης. Αυτό σημαίνει ότι μια θέση μπορεί να περιέχει πολλαπλούς τύπους.
tuple : Tuple(Int32 | String, String, Char) = {1, "foo", 'c'}
Μπορείς να δημιουργήσεις μια πλειάδα από έναν πίνακα χρησιμοποιώντας τη μέθοδο from της κλάσης Tuple.
Αυτό απαιτεί να καθοριστεί ο τύπος της πλειάδας.
array = [1, "foo", 'c']
tuple = Tuple(Int32, String, Char).from(array)
Μπορείς να μετατρέψεις μια πλειάδα σε πίνακα χρησιμοποιώντας τη μέθοδο to_a.
Ο τύπος στοιχείου του πίνακα που προκύπτει είναι η ένωση του τύπου κάθε πεδίου της πλειάδας.
tuple = {1, "foo", 'c'}
array = tuple.to_a
array # => [1, "foo", 'c']
Όπως και οι πίνακες, οι πλειάδες έχουν θέσεις που ξεκινούν από το μηδέν, που σημαίνει ότι το πρώτο στοιχείο βρίσκεται στη θέση 0.
Ωστόσο, σε αντίθεση με τους πίνακες, ο τύπος κάθε στοιχείου είναι σταθερός και γνωστός κατά τον χρόνο μεταγλώττισης, επομένως όταν χρησιμοποιείς μια θέση για να ανατρέξεις σε μια πλειάδα, ο τύπος του στοιχείου είναι συγκεκριμένος για εκείνη τη θέση.
Για να αποκτήσεις πρόσβαση σε ένα στοιχείο μιας πλειάδας, μπορείς να χρησιμοποιήσεις τον τελεστή [].
array = [1, "foo", 'c']
array[0] # => 1
typeof(array[0]) # => Int32 | String | Char
tuple = {1, "foo", 'c'}
tuple[0] # => 1
typeof(tuple[0]) # => Int32
Μια άλλη διαφορά όσον αφορά την πρόσβαση σε στοιχεία από πίνακες είναι ότι αν καθοριστεί η θέση, τότε ο μεταγλωττιστής θα ελέγξει ότι η θέση βρίσκεται εντός των ορίων της πλειάδας. Αυτό σημαίνει ότι θα λάβεις σφάλμα κατά τον χρόνο μεταγλώττισης αντί για σφάλμα κατά τον χρόνο εκτέλεσης.
tuple = {1, "foo", 'c'}
tuple[3]
# => Error: index out of bounds for Tuple(Int32, String, Char) (3 not in -3..2)
Ωστόσο, αν η θέση είναι αποθηκευμένη σε μια μεταβλητή, τότε ο μεταγλωττιστής δε θα μπορεί να ελέγξει αν η θέση βρίσκεται εντός των ορίων της πλειάδας κατά τον χρόνο μεταγλώττισης και αντ' αυτού θα δώσει σφάλμα κατά τον χρόνο εκτέλεσης.
Μπορείς να πάρεις μια υποπλειάδα μιας πλειάδας χρησιμοποιώντας τον τελεστή [] με ένα διάστημα.
Αυτό που επιστρέφεται είναι μια νέα πλειάδα με τα στοιχεία από το διάστημα που καθορίστηκε.
Το διάστημα πρέπει να δοθεί κατά τον χρόνο μεταγλώττισης, αλλιώς ο μεταγλωττιστής δε θα μπορεί να γνωρίζει τους τύπους των στοιχείων της υποπλειάδας.
Αυτό σημαίνει ότι το διάστημα πρέπει να είναι ένα κυριολεκτικό διάστημα και όχι ανατεθειμένο σε μια μεταβλητή.
tuple = {1, "foo", 'c'}
subtuple = tuple[0..1] # Tuple(Int32, String)
i = 0..1
tuple[i]
# Error: Tuple#[](Range) can only be called with range literals known at compile-time
Οι πλειάδες είναι χρήσιμες όταν θέλεις να ομαδοποιήσεις έναν σταθερό αριθμό τιμών μαζί, όπου οι τύποι των τιμών είναι γνωστοί κατά τον χρόνο μεταγλώττισης. Αυτό συμβαίνει επειδή οι πλειάδες απαιτούν λιγότερη μνήμη και είναι ταχύτερες από τους πίνακες λόγω του αμετάβλητου χαρακτήρα τους. Μια άλλη περίπτωση χρήσης είναι η επιστροφή πολλαπλών τιμών από μια μέθοδο. Αυτό είναι ιδιαίτερα χρήσιμο αν οι τιμές έχουν διαφορετικούς τύπους, καθώς κάθε θέση της πλειάδας μπορεί να έχει διαφορετικό τύπο.
Οι πλειάδες δεν πρέπει να χρησιμοποιούνται όταν χρειάζεται μια δομή δεδομένων που μπορεί να μεγαλώσει ή να μικρύνει σε μέγεθος ή χρειάζεται συχνά τροποποίηση.
Τα σύμβολα είναι ονομασμένα αναγνωριστικά που μπορούν να χρησιμοποιηθούν για να αναφέρονται σε μια τιμή.
Τα σύμβολα δημιουργούνται μέσω ενός κυριολεκτικού συμβόλου, το οποίο γίνεται βάζοντας έναν χαρακτήρα : μπροστά από ένα όνομα, π.χ. :foo.
Επιτρέπουν επίσης να γραφτούν με εισαγωγικά, π.χ. :"foo", που επιτρέπει, για παράδειγμα, κενά στο όνομα.
:foo # => :foo
:"foo boo" # => :"foo boo"
:foo == :"foo" # => true
Τα σύμβολα χρησιμοποιούνται σε πολλά σημεία της γλώσσας, μεταξύ άλλων ως κλειδιά σε namedtuples και για να αναπαριστούν ονόματα μεθόδων και μεταβλητών.
Τα σύμβολα στην Crystal είναι αρκετά διαφορετικά από τη Ruby. Στην Crystal ένα σύμβολο είναι ένας τύπος σταθεράς και επομένως ανατίθεται κατά τον χρόνο μεταγλώττισης. Αυτό σημαίνει ότι τα σύμβολα δε μπορούν να δημιουργηθούν δυναμικά, κάτι που είναι δυνατό στη Ruby.
Τα σύμβολα στην Crystal αναπαρίστανται ως Int32, γεγονός που τα κάνει πολύ αποδοτικά.
Τα σύμβολα μπορούν να μετατραπούν σε συμβολοσειρές, αλλά όχι το αντίστροφο. Αυτό συμβαίνει επειδή τα σύμβολα δημιουργούνται κατά τον χρόνο μεταγλώττισης και οι συμβολοσειρές δημιουργούνται κατά τον χρόνο εκτέλεσης.
:foo.to_s # => "foo"
Ενώ ετοιμάζεσαι να ψήσεις μπισκότα για τους φίλους σου, διαπίστωσες ότι πρέπει να μετατρέψεις κάποιες από τις μετρήσεις που χρησιμοποιεί η συνταγή. Γνωρίζοντας μόνο το μετρικό σύστημα, πρέπει να βρεις έναν τρόπο να μετατρέψεις συνηθισμένες αμερικανικές μετρήσεις ψησίματος σε χιλιοστόλιτρα (mL) για δική σου ευκολία.
Χρησιμοποίησε αυτόν τον πίνακα μετατροπών για τη λύση σου:
| Μονάδα προς μετατροπή | όγκος | σε χιλιοστόλιτρα (mL) |
|---|---|---|
| mL | 1 | 1 |
| αμερικανικό φλιτζάνι | 1 | 240 |
| αμερικανική υγρή ουγγιά | 1 | 30 |
| αμερικανικό κουταλάκι του γλυκού | 1 | 5 |
| αμερικανική κουταλιά της σούπας | 1 | 15 |
Καθώς είσαι ένας ταλαντούχος εκπαιδευόμενος προγραμματιστής, αποφασίζεις να χρησιμοποιήσεις τα χιλιοστόλιτρα ως ενδιάμεση μονάδα για να διευκολύνεις τη μετατροπή από οποιαδήποτε μονάδα της λίστας σε οποιαδήποτε άλλη (ακόμη και στην ίδια).
Υλοποίησε τη μέθοδο KitchenCalculator.get_volume.
Δεδομένης μιας πλειάδας ζεύγους όγκου, θα πρέπει να επιστρέφει μόνο το αριθμητικό μέρος.
KitchenCalculator.get_volume({:cup, 2.0})
# => 2.0
Υλοποίησε τη μέθοδο KitchenCalculator.to_milliliter.
Δεδομένης μιας πλειάδας ζεύγους όγκου, θα πρέπει να μετατρέπει τον όγκο σε χιλιοστόλιτρα χρησιμοποιώντας τον πίνακα μετατροπών.
KitchenCalculator.to_milliliter({:cup, 2.5})
# => {:milliliter, 600.0}
Υλοποίησε τη μέθοδο KitchenCalculator.from_milliliter.
Δεδομένης μιας πλειάδας ζεύγους όγκου και της επιθυμητής μονάδας, θα πρέπει να μετατρέπει τον όγκο στην επιθυμητή μονάδα χρησιμοποιώντας τον πίνακα μετατροπών.
KitchenCalculator.from_milliliter({:milliliter, 1320.0}, :cup)
# => {:cup, 5.5}
Υλοποίησε τη μέθοδο KitchenCalculator.convert.
Δεδομένης μιας πλειάδας ζεύγους όγκου και της επιθυμητής μονάδας, θα πρέπει να μετατρέπει τον δεδομένο όγκο στην επιθυμητή μονάδα.
KitchenCalculator.convert({:teaspoon, 9.0}, :tablespoon)
# => {:tablespoon, 3.0}
Γράψου στο Exercism για να μάθεις και να κατακτήσεις Crystal με 26 έννοιες142 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.