A függvény lehetővé teszi, hogy a kódot egy újrahasznosítható egységbe rendezd.
A func kulcsszóból, a függvény nevéből, valamint zárójelben egy vesszővel elválasztott, nulla vagy több paraméterből és azok típusából áll.
Minden paraméternél explicit módon meg kell adni a típust; a paramétereknél nincs típuskövetkeztetés. A paramétereknek nincs alapértelmezett értékük, ezért minden függvényparaméter kötelező.
import "fmt"
// No parameters
func PrintHello() {
fmt.Println("Hello")
}
// One parameter
func PrintHelloName(name string) {
fmt.Println("Hello " + name)
}
Az azonos típusú paramétereket együtt is deklarálhatod, egyetlen típusmegadással a végükön.
import "fmt"
func PrintGreetingName(greeting, name string) {
fmt.Println(greeting + " " + name)
}
Nézzünk meg gyorsan két fogalmat, amelyet gyakran összekevernek: a parameters és az arguments.
A függvényparaméterek a függvény szignatúrájában megadott nevek, például a fenti PrintGreetingName függvényben a greeting és a name.
A függvényargumentumok azok a konkrét értékek, amelyeket a függvény meghívásakor adunk át a függvény paramétereinek.
Az alábbi példában például a "Hello" és a "Katrina" azok az argumentumok, amelyeket a greeting és a name paraméternek adunk át:
PrintGreetingName("Hello", "Katrina")
A függvényparamétereket nulla vagy több visszatérési érték követi, amelyeknél szintén explicit módon meg kell adni a típust.
Az egyetlen visszatérési értéket zárójel nélkül írjuk, a többit zárójelbe tesszük.
A függvények a return kulcsszó használatával adják vissza az értékeket a hívó kódnak.
Egy függvényben több return utasítás is lehet.
A függvény végrehajtása azonnal véget ér, amint elér egy ilyen return utasítást.
Ha egy függvény több értéket ad vissza, azokat vesszővel választjuk el.
A több visszatérési érték idiomatikus használatáról bővebb információt a hivatkozott fogalomnál találsz.
func Hello(name string) string {
return "Hello " + name
}
func HelloAndGoodbye(name string) (string, string) {
return "Hello " + name, "Goodbye " + name
}
Egy függvényt úgy hívunk meg, hogy megadjuk a függvény nevét, és zárójelben átadunk egy-egy argumentumot a függvény minden paraméteréhez.
import "fmt"
// No parameters, no return value
func PrintHello() {
fmt.Println("Hello")
}
// Called like this:
PrintHello()
// One parameter, one return value
func Hello(name string) string {
return "Hello " + name
}
// Called like this:
greeting := Hello("Dave")
// Multiple parameters, multiple return values
func SumAndMultiply(a, b int) (int, int) {
return a+b, a*b
}
// Called like this:
aplusb, atimesb := SumAndMultiply(a, b)
A paraméterekhez hasonlóan a visszatérési értékeket is elnevezheted, ez azonban nem kötelező.
Ha nevesített visszatérési értékeket használsz, egy argumentum nélküli return utasítás ezeket az értékeket adja vissza.
Ezt nevezik „csupasz” visszatérésnek.
func SumAndMultiplyThenMinus(a, b, c int) (sum, mult int) {
sum, mult = a+b, a*b
sum -= c
mult -= c
return
}
Az is fontos, hogy tisztázzuk az érték szerinti és a referencia szerinti átadás fogalmát.
Először tisztázzuk az érték szerinti átadást.
Az alábbi példában, amikor a val változót átadjuk a MultiplyByTwo függvénynek, a val egy másolatát adjuk át.
Emiatt a newVal értéke a frissített 4 lesz, az eredeti val változó viszont továbbra is 2.
A színfalak mögött a Go lényegében másolatot készít az eredeti értékről, így a függvény csak ezt a másolatot, azaz v-t módosítja.
val := 2
func MultiplyByTwo(v int) int {
v = v * 2
return v
}
newVal := MultiplyByTwo(val)
// newval is 4, val is still 2 because only a copy of its value was passed into the function
Szigorúan véve a Go-ban minden argumentum érték szerint adódik át, azaz másolat készül a függvénynek átadott értékről vagy adatról.
Ha viszont nem szeretnél másolatot készíteni a függvénynek átadott adatról, és magát az adatot szeretnéd módosítani a függvényben,
akkor pointers argumentumokat, azaz referencia szerinti átadást kell használnod.
A referencia szerinti átadáshoz pointer-t használunk.
Ha pointer argumentumokat adunk át egy függvénynek,
akkor a függvénynek átadott mögöttes adatot is módosíthatjuk, ahelyett hogy csak az adat egy másolatán dolgoznánk.
Egyelőre elég annyit tudnod, hogy a pointer típusokat a függvény szignatúrájában a típus előtti * jelről ismerheted fel.
func HandlePointers(x, y *int) {
// Some logic to handle integer values referenced by pointers x and y
}
Ha a pointer fogalma zavarónak tűnik, ne aggódj.
A tantervben később egy külön fejezet segít, hogy mesterien bánj a pointerekkel.
Vedd figyelembe, hogy a slices és a maps kivételt képez a fent említett szabály alól.
Amikor egy slice-ot vagy egy map-et argumentumként adunk át egy függvénynek, azokat pointer típusként kezeli, még akkor is, ha a típusban nincs explicit *.
Ez azt jelenti, hogy ha egy slice-t vagy map-et átadunk egy függvénynek, és módosítjuk a mögöttes adatait,
a változások az eredeti slice-on vagy map-en is megjelennek.
A Go-ban a függvények első osztályú állampolgárok, ami rendkívül erőssé teszi őket. Számos más fogalom is kapcsolódik a függvényekhez, például a metódusok és a névtelen függvények, amelyekkel később, az utad során találkozni fogsz.