FREE

ΕΝΟΤΗΤΑ 11 GO - Functions (Part 1)

Στο σημερινό δωρεάν μάθημα GO θα δούμε πως δημιουργούμε τα δικά μας functions. Θα ξεκινήσουμε με την πιο απλή μορφή που μπορεί να έχει ένα λειτουργικό function και σταδιακά θα φτάσουμε σε πιο προχωρημένες δομές functions όπως εκείνες που δέχονται μεταβλητό αριθμό παραμέτρων και επιστρέφουν πολλαπλά αποτελέσματα.

Η δήλωση μιας function ξεκινάει με την λέξη κλειδί func και αμέσως μετά ακολουθούν το όνομα που θέλουμε να δώσουμε στην function και ένα ζευγάρι παρενθέσεων. Τέλος ανάμεσα σε άγκιστρα γράφουμε τον κώδικα που θα εκτελέσει η function όταν την καλέσουμε. Για να καλέσουμε την function μέσα από το κύριο πρόγραμμα μας δεν έχουμε παρά να γράψουμε το όνομα της function ακολουθούμενο από παρενθέσεις. Ας δούμε ένα απλό παράδειγμα.

main.go


package main

import "fmt"

func hello(){
    fmt.Println("Welcome to GO free lessons")
}

func main() {
    hello()
}

Output


Welcome to GO free lessons

Όταν καλούμε την hello( ) function δεν βάζουμε μπροστά το όνομα του πακέτου εάν η function ανήκει στο ίδιο πακέτο όπως η main( ). Γράφοντας, για παράδειγμα, main.hello( ) θα προκαλέσει λάθος στην εκτέλεση του προγράμματος.

Οι κανόνες ονομασίας μιας function είναι ίδιοι με εκείνους που χρησιμοποιούμε για να ονομάσουμε τις μεταβλητές μας.

  • Το όνομα πρέπει να ξεκινάει με γράμμα και μετά μπορεί να περιλαμβάνει οποιοδήποτε γράμμα ή αριθμό.
  • Τα ονόματα των functions που ξεκινάνε με κεφαλαίο γράμμα μπορούν να χρησιμοποιηθούν και εκτός του πακέτου στο οποίο ανήκουν. Αν η χρήση του είναι μόνο για το πακέτο στο οποίο έχουν οριστεί (όπως στο παράδειγμα μας) τότε το πρώτο γράμμα πρέπει να είναι πεζό (μικρό).
  • Αν το όνομα της function περιλαμβάνει πολλαπλές λέξεις τότε συνηθίζεται να χρησιμοποιούμε camelCase.

Μπορούμε επίσης να περάσουμε τιμές σε μια function ορίζοντας παραμέτρους. Η παράμετρος είναι μια τοπική μεταβλητή της function και η τιμή της ορίζεται όταν καλούμε την function. Μπορούμε να ορίσουμε μια ή και περισσότερες παραμέτρους μέσα στην παρένθεση της function. Το κόμμα χωρίζει τον ορισμό της μιας παραμέτρου από την άλλη.

Όπως κάνουμε και για τον ορισμό κάθε μεταβλητής, έτσι και όταν ορίζουμε παραμέτρους πρέπει να ορίσουμε και το type για την κάθε παράμετρο ξεχωριστά (π.χ float64, bool, κτλ).

Τέλος, κάθε function έχει την δυνατότητα να μας γυρίσει μια ή και περισσότερες τιμές πίσω στο πρόγραμμα μετά το τέλος της εκτέλεσή της. Ο κανόνας της GO απαιτεί από εμάς να ορίσουμε το data type της τιμής που μας επιστρέφει η function.

Ας δούμε όμως ένα απλό παράδειγμα μέσα από το οποίο μπορούμε να δούμε όλη την θεωρία για την οποία έχουμε μιλήσει μέχρι τώρα.

main.go


package main

import "fmt"

func addition(x int, y int) int{
    return x + y
}

func main() {
    x:= addition(5, 15)
    fmt.Println("result is", x)
}

Output


result is 20

Η γενικότερη ιδέα πίσω από την λειτουργία μιας function είναι να λαμβάνει input και να μας επιστρέφει ένα output. Ο κώδικας μέσα στην function αναλαμβάνει να κάνει όλες τις απαραίτητες πράξεις που χρειάζονται για να λάβουμε το σωστό αποτέλεσμα. Στο παράδειγμα μας, η λέξη κλειδί func ενημερώνει τον compiler για την αρχή της function. Το όνομα της function είναι addition. Μέσα στην παρένθεση ορίζουμε ότι η function θα δέχεται δύο int παραμέτρους, ενώ έξω, και αμέσως μετά την παρένθεση, ορίζουμε ότι η function θα μας επιστρέφει μια int τιμή. Μέσα στα άγκιστρα ορίζουμε τον κώδικα που θα εκτελεί η function. Επειδή έχουμε ορίσει ότι η function θα μας επιστρέφει μια int τιμή, τότε είναι απαραίτητη η χρήση της λέξης return. Με την return μπορούμε να επιστρέψουμε το αποτέλεσμα ενός expression ή την τιμή μιας μεταβλητής. Δεν είναι όμως απαραίτητο όλες οι functions να επιστρέφουν κάτι. Μπορούν απλά να εκτελούν πράξεις χωρίς να επιστρέφουν τιμή πίσω στο πρόγραμμα. Σε αυτή την περίπτωση δεν χρησιμοποιούμε το return μέσα στο κώδικα αλλά ούτε και δηλώνουμε return data type στον ορισμό της function. Η πρώτη γραμμή ορισμού της function ονομάζεται το signature της function.

Όταν λέμε ότι μια function δεν επιστρέφει τίποτα πίσω στο πρόγραμμα σημαίνει ότι δεν έχει νόημα να αναθέσουμε το αποτέλεσμα της function σε μια μεταβλητή.

x := myfunction( )

Το γεγονός ότι η function τυπώνει το αποτέλεσμα στο terminal δεν σημαίνει ότι επιστρέφει κάτι πίσω στο πρόγραμμα μας. Ελπίζω με αυτή την γρήγορη επεξήγηση να είναι ξεκάθαρη η έννοια του return όπως χρησιμοποιείται σε μια function.

Ένα παράδειγμα μιας function που κάνει κάποιες πράξεις αλλά δεν επιστρέφει τίποτα πίσω στο πρόγραμμα μας είναι το εξής:

main.go

            
package main

import "fmt"

func goLang(){
    for i := 1; i <=30; i++{
        if i%15 == 0 {
            fmt.Println("GOLang")
        }else if i%3==0 {
            fmt.Println("GO")
        }else if i%5==0  {
            fmt.Println("Lang")
        }else {
            fmt.Println(i)
        }
    }
}

func main() {
    goLang()
}
                
            
            

Output

            
1
2
GO
4
Lang
GO
7
8
GO
Lang
11
GO
13
14
GOLang
16
17
GO
19
Lang
GO
22
23
GO
Lang
26
GO
28
29
GOLang
                
            
            

Οι functions στην GO μπορούν να επιστρέψουν πολλαπλές τιμές ταυτόχρονα αφού πρώτα οριστούν στο function signature. Αυτό έχει σαν αποτέλεσμα το return statement μέσα στην function να επιστρέφει περισσότερες από μια τιμές. Ας δούμε ένα απλό παράδειγμα μιας function που ενώ δεν δέχεται καμία input παράμετρο επιστρέφει μια int και μια string τιμή. Οι τιμές επιστρέφονται πίσω στο πρόγραμμα μέσω της return statement και χωρίζονται με κόμμα.

main.go

    
package main

import "fmt"

func championTeam()(int, string){
    i:=2
    s:="Liverpool"
    return i, s
}

func main() {
    goals, team := championTeam()
    fmt.Printf("%v won the championship by scoring %v goals", team, goals)
}
    
    

Output

    
Liverpool won the championship by scoring 2 goals
    
    

Στην GO έχουμε επίσης την δυνατότητα να περνάμε σε μια function μεταβλητό αριθμό παραμέτρων αρκεί όλες να είναι το ίδιο data type. Ο τρόπος που ορίζουμε σε μια function να δέχεται πολλαπλές παραμέτρους είναι με την χρήση τριών τελείων ( . . . ). Ας δούμε μέσα από ένα απλό παράδειγμα πως ακριβώς χρησιμοποιούμε τις variadic functions όπως ονομάζονται. Μέσα στο κώδικα χρησιμοποιούμε την έννοια του slice για να διαβάσουμε τις τιμές. Μην ανησυχείτε για την έννοια του slice. Θα την αναλύσουμε σε μελλοντική ενότητα μαζί με τους array και τα maps.

main.go

    
package main

import "fmt"

func sumNumbers(numbers ...int) int{
    total :=0
    for _, number := range numbers {
        total += number
    }
    return total
}

func main() {
    result := sumNumbers(1, 2, 3, 4)
    fmt.Printf("The result is %v", result)
}
    
    

Output

    
The result is 10
    
    

Πριν κλείσουμε το πρώτο μέρος της αναφοράς μας στα functions της GO, θα αναφερθούμε σε μια ακόμα ιδιαίτερη κατηγόρια τους που είναι αυτή των named return values. Χρησιμοποιώντας named return values μπορούμε να αναθέσουμε τιμές σε τοπικές μεταβλητές της function πριν επιστρέψουμε τις τιμές τους πίσω στο πρόγραμμα. Για να χρησιμοποιήσουμε σωστά named return values, πρέπει πρώτα να ορίσουμε τις μεταβλητές στο signature της function σαν return values.

main.go

    
package main

import "fmt"

func myName()(x, y string){
    x = "Michail"
    y="Kassapoglou"
    return
}

func main() {
    fmt.Println(myName())
}
        
    
    

Output

    
Michail Kassapoglou
    
    

Μέσα στην function, αναθέτουμε τιμές στις named variables. Επειδή χρησιμοποιούμε named return values δεν είναι ανάγκη να δηλώσουμε τις μεταβλητές στο return statement. Γράφοντας απλά return, η function θα μας επιστρέψει όλες τις μεταβλητές. Αυτό ονομάζεται naked return statement.