Διαμορφώνοντας το output με Println, Printf και Sprintf

Από τις πρώτες ασκήσεις προγραμματισμού που μαθαίνει κανείς είναι αυτές που σχετίζονται με την εκτύπωση διαφόρων δεδομένων στο τερματικό. Η πιο “κλασσική” συνάρτηση που υπάρχει σε όλες τις γλώσσες προγραμματισμού είναι η print. Αυτό θα είναι το αντικείμενο του άρθρου σήμερα; να μάθουμε πώς να κάνουμε print διαφόρους τύπους δεδομένων στην golang και να εξικοιωθούμε με τρεις από τις διάφορες παραλλαγές αυτής (Println, Printf και Sprintf). Προφανώς και υπάρχουν κι άλλες, αλλά αυτές οι τρεις χρησιμοποιούνται πιο συχνά. Πάμε λοιπόν! Ας δούμε το παρακάτω κομμάτι κώδικα:

// Ορισμοί πακέτων κλπ παραλείπονται για ευνόητους λόγους
func main() {
    var x, y, area float64
    // Υπολόγισε το εμβαδό
    x = 4.2
    y = 3.0
    area = y * x
    fmt.Println(area, "τετραγωνικά μέτρα")
}

Κάνε κλικ εδώ για να τρέξεις τον κώδικα.

Η έξοδος είναι:

12.600000000000001 τετραγωνικά μέτρα

Αν και το παραπάνω πρόγραμμα δουλεύει, αυτό δεν σημαίνει ότι δεν έχει προβλήματα:

Σε αυτό το άρθρο θα μιλήσω για το πρώτο μέρος του προβλήματος, καθώς έχω σκοπό να γράψω για συναρτήσεις σε άλλο άρθρο. Η λύση που βρήκα είναι απλή και μπακάλικη: Στρογγυλοποίηση σε δύο δεκαδικά. Προσωπικά μου αρκούν - και νομίζω για τον περισσότερο κόσμο είναι ΟΚ.

Printf

Το πακέτο fmt διαθέτει μία συνάρτηση που λέγεται Printf η οποία σημαίνει κάτι όπως print with formatting.

// Printf formats according to a format specifier and writes to standard output.
// It returns the number of bytes written and any write error encountered.
func Printf(format string, a ...interface{}) (n int, err error) {
	return Fprintf(os.Stdout, format, a...)
}

Συνεπώς το παραπάνω παράδειγμα μπορεί να διορθώθεί με:

fmt.Printf("%0.2f τετραγωνικά μέτρα\n", area)

Έξοδος:

12.60 τετραγωνικά μέτρα

Sprintf

Η Sprintf είναι μία ακόμα συνάρτηση του fmt package, η οποία λειτουργεί όπως και η Printf, με την διαφορά ότι επιστρέφει το string χωρίς ντε-και-καλά να το κάνει printing στην έξοδο. Για αυτό προφανώς χρησιμοποιείται όταν θέλει κανείς να αποθηκεύσει ένα φορμαρισμένο string.

// Sprintf formats according to a format specifier and returns the resulting string.
func Sprintf(format string, a ...interface{}) string {
	p := newPrinter()
	p.doPrintf(format, a)
	s := string(p.buf)
	p.free()
	return s
}

Συνεπώς το παραπάνω παράδειγμα μπορεί να διορθωθεί με:

resultStr := fmt.Sprintf("%0.2f τετραγωνικά μέτρα\n", area)
fmt.Printf(resultStr)

Έξοδος:

12.60 τετραγωνικά μέτρα

Από ότι φαίνεται και οι δύο συναρτήσεις, fmt.Printf() και fmt.Sprintf() είναι ικανές να διορθώσουν το πρόβλημα που είχα, μειώνοντας τα δεκαδικά ψηφία σε μόνο δύο. Στην περίπτωση που σας φαίνεται περίεργη η υλοποίησή τους, τότε ίσως δεν ξέρετε να χρησιμοποιείτε τα formatting verbs. Για παράδειγμα, όλες αυτές οι Printότιναναι συναρτήσεις, συνήθως έχουν μία σύνταξη όπως το παράδειγμά μας: %0.2f. Σε αυτό το παράδειγμα:

Μερικά άλλα παραδείγματα:

// verbs: %s και %d
// values: "ΠΑΟΚ" και 2009
fmt.Printf("Ο %s πήρε πρωτάθλημα το %d\n", "ΠΑΟΚ", 2009)

// verbs: %f
// values: 12.600000
fmt.Printf("%f τετραγωνικά μέτρα\n", 4.2*3.0)

Έξοδος:

Ο ΠΑΟΚ πήρε πρωτάθλημα το 2009
12.600000 τετραγωνικά μέτρα

Διαβάζοντας το documentation του fmt package, μερικά από τα πιο συνήθες verbs είναι τα εξής:

func main() {
	fmt.Printf("Δεκαδικός: %f\n", 3.1415)
	fmt.Printf("Ακέραιος: %d\n", 13)
	fmt.Printf("String: %s\n", "Μα ποιος λέει αλφαριμητικό;")
	fmt.Printf("Boolean: %t\n", false)
	fmt.Printf("Τύπος: %T %T %T %T\n", 3.1415, 13, "pizza", true)
	fmt.Printf("Τιμές: %v %v %v\n", 1.13, "\t", true)
	fmt.Printf("Τιμές: %#v %#v %#v\n", 1.13, "\t", true)
}

Τρέξτε τον κώδικα κάνοντας κλικ εδώ

Έξοδος:

Δεκαδικός: 3.141500
Ακέραιος: 13
String: Μα ποιος λέει αλφαριμητικό;
Boolean: false
Τύπος: float64 int string bool
Τιμές: 1.13 	 true
Τιμές: 1.13 "\t" true

Aπό αυτά αξίζει να σημειώσετε την χρήση του %#v η οποία στην ουσία επιστρέφει αυτούσια την τιμή έτσι όπως γράφεται στον κώδικα της Go. Κάτι τέτοιο είναι χρήσιμο σε περίπτώσεις debugging.

Δεκαδικά και character padding

Κλείνοντας, θέλω να μιλήσω για την λύση που δώσαμε νωρίτερα χρησιμοποιώντας το %0.2f verb, καταφέρνοντας έτσι να περιορίσουμε τα δεκαδικά ψηφία σε μόνο 2. Η ίδια λογική μπορεί να εφαρμοστεί και για strings και ιδιαίτερα σε περιπτώσεις όπου θέλουμε να έχουμε ομοιόμορφη στοίχιση και άλλα περίεργα nerd-ουλίστικα θέματα που έχουν να κάνουν με την έξοδο ενός προγράμματος στο τερματικό. Για παράδειγμα:

fmt.Printf("%30s | %s\n", "Προσθήκη στο καλάθι", "Τιμή")
fmt.Printf("- - - - - - - - - - - - - - - - - - - - - -\n")
fmt.Printf("%30s | %0.2f EUR\n", "Πίτσα Σπέσιαλ με έξτρα κασέρι", 7.80)
fmt.Printf("%30s | %0.2f EUR\n", "Πίτα γύρο με πατάτες", 3.5)
fmt.Printf("%30s | %0.2f EUR\n", "Φαλάφελ για Vegan", 4.50)

Τρέξτε τον κώδικα εδώ

Έξοδος:

	   Προσθήκη στο καλάθι | Τιμή
- - - - - - - - - - - - - - - - - - - - - -
 Πίτσα Σπέσιαλ με έξτρα κασέρι | 7.80 EUR
          Πίτα γύρο με πατάτες | 3.50 EUR
             Φαλάφελ για Vegan | 4.50 EUR

Όπως βλέπετε μπορούμε να χρησιμοποιήσουμε αυτό το τρικ για να κάνουμε padding. Καλή φάση!

Σχόλια powered by Disqus