Tracks
/
Go
Go
/
Lehrplan
/
Funktionen
Fu

Funktionen in Go

1 Übung

Über Funktionen

Mit einer Funktion kannst du Code zu einer wiederverwendbaren Einheit zusammenfassen. Sie besteht aus dem func-Schlüsselwort, dem Namen der Funktion und einer durch Kommas getrennten Liste von null oder mehr Parametern samt Typen in runden Klammern.

Funktionsparameter

Alle Parameter müssen explizit typisiert werden; für Parameter gibt es keine Typinferenz. Für Parameter gibt es keine Standardwerte, deshalb sind alle Funktionsparameter erforderlich.

import "fmt"

// No parameters
func PrintHello() {
    fmt.Println("Hello")
}

// One parameter
func PrintHelloName(name string) {
  fmt.Println("Hello " + name)
}

Parameter desselben Typs kannst du zusammen deklarieren, gefolgt von einer einzigen Typangabe.

import "fmt"

func PrintGreetingName(greeting, name string) {
  fmt.Println(greeting + " " + name)
}

Parameter vs. Argumente

Schauen wir uns kurz zwei Begriffe an, die oft verwechselt werden: parameters und arguments. Funktionsparameter sind die Namen, die in der Signatur der Funktion definiert werden, wie greeting und name in der Funktion PrintGreetingName oben. Funktionsargumente sind die konkreten Werte, die beim Aufruf der Funktion an die Funktionsparameter übergeben werden. Zum Beispiel sind im folgenden Beispiel "Hello" und "Katrina" die Argumente, die an die Parameter greeting und name übergeben werden:

PrintGreetingName("Hello", "Katrina")

Rückgabewerte

Auf die Funktionsparameter folgen null oder mehr Rückgabewerte, die ebenfalls explizit typisiert werden müssen. Einzelne Rückgabewerte stehen ohne Klammern, mehrere Rückgabewerte werden in runde Klammern gesetzt. Werte werden mit dem return-Schlüsselwort aus Funktionen an den aufrufenden Code zurückgegeben. Eine Funktion kann mehrere return-Anweisungen enthalten. Die Ausführung der Funktion endet, sobald sie auf eine dieser return-Anweisungen trifft. Wenn mehrere Werte aus einer Funktion zurückgegeben werden sollen, werden sie durch Kommas getrennt. Mehr über die idiomatische Verwendung von mehreren Rückgabewerten findest du im verlinkten Konzept.

func Hello(name string) string {
  return "Hello " + name
}

func HelloAndGoodbye(name string) (string, string) {
  return "Hello " + name, "Goodbye " + name
}

Funktionen aufrufen

Eine Funktion rufst du auf, indem du den Funktionsnamen angibst und für jeden Parameter der Funktion ein Argument in runden Klammern übergibst.

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)

Benannte Rückgabewerte und nackte Rückgabe

Wie Parameter können auch Rückgabewerte optional benannt werden. Wenn benannte Rückgabewerte verwendet werden, gibt eine return-Anweisung ohne Argumente diese Werte zurück. Das nennt man eine „nackte“ Rückgabe.

func SumAndMultiplyThenMinus(a, b, c int) (sum, mult int) {
    sum, mult = a+b, a*b
    sum -= c
    mult -= c
    return
}

Übergabe per Wert vs. Übergabe per Referenz

Außerdem ist es wichtig, das Konzept der Übergabe per Wert und der Übergabe per Referenz zu klären.

Klären wir zuerst die Übergabe per Wert. Wenn wir im folgenden Beispiel die Variable val an die Funktion MultiplyByTwo übergeben, übergeben wir eine Kopie von val. Deshalb hat newVal den aktualisierten Wert 4, aber die ursprüngliche Variable val ist immer noch 2. Im Hintergrund erstellt Go im Wesentlichen eine Kopie des ursprünglichen Werts, sodass die Funktion nur diese Kopie, also v, verändert.

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

Streng genommen werden in Go alle Argumente per Wert übergeben, das heißt, von dem Wert oder den Daten, die an die Funktion übergeben werden, wird eine Kopie erstellt. Wenn du aber keine Kopie der Daten erstellen möchtest, die an eine Funktion übergeben werden, und die Daten in der Funktion ändern willst, dann solltest du pointers als Argumente verwenden, also die Übergabe per Referenz.

Pointer

Wir verwenden einen pointer, um die Übergabe per Referenz zu erreichen. Indem wir Argumente vom Typ pointer an eine Funktion übergeben, können wir die zugrunde liegenden Daten, die in die Funktion übergeben wurden, verändern, statt nur mit einer Kopie der Daten zu arbeiten.

Für den Moment reicht es zu wissen, dass du Pointer-Typen am * vor dem Typ in der Funktionssignatur erkennen kannst.

func HandlePointers(x, y *int) {
    // Some logic to handle integer values referenced by pointers x and y
}

Wenn dir das Konzept pointer verwirrend erscheint, keine Sorge. Wir haben später im Lehrplan einen eigenen Abschnitt, der dir hilft, Pointer zu meistern.

Ausnahmen

Beachte, dass slices und maps Ausnahmen von der oben genannten Regel sind. Wenn wir einen slice oder eine map als Argumente an eine Funktion übergeben, werden sie wie Pointer-Typen behandelt, obwohl im Typ kein explizites * steht. Das bedeutet: Wenn wir einen Slice oder eine Map an eine Funktion übergeben und deren zugrunde liegende Daten ändern, werden die Änderungen im ursprünglichen Slice bzw. in der ursprünglichen Map sichtbar.

Andere Arten von Funktionen

Funktionen sind in Go Bürger erster Klasse, was sie sehr mächtig macht. Rund um Funktionen gibt es noch eine Reihe weiterer Konzepte wie Methoden und anonyme Funktionen, die dir später noch begegnen werden.

Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab

Lerne Funktionen