Functies maken

Voltooid

In Go kunt u met functies een set instructies groeperen die u kunt aanroepen vanuit andere onderdelen van uw toepassing. In plaats van een programma met veel instructies te maken, kunt u functies gebruiken om de code te ordenen en beter leesbaar te maken. Meer leesbare code is ook beter te onderhouden.

Tot nu toe hebben we de fmt.Println() functie aangeroepen en hebben we code in de main() functie geschreven. In deze sectie verkennen we hoe u aangepaste functies kunt maken. We bekijken ook enkele andere technieken die u kunt gebruiken met functies in Go.

Hoofdfunctie

De functie waarmee u hebt gewerkt, is de main() functie. Alle uitvoerbare programma's in Go hebben deze functie omdat het het beginpunt van het programma is. U kunt slechts één main() functie in uw programma hebben. Als u een Go-pakket maakt, hoeft u geen functie te schrijven main() . In een toekomstige module wordt uitgelegd hoe u pakketten maakt.

Voordat we aan de slag gaan met de basisprincipes van het maken van aangepaste functies in Go, gaan we eens kijken naar een cruciaal aspect van de main() functie. Zoals u misschien hebt opgemerkt, heeft de main() functie geen parameters en retourneert niets. Maar dat betekent niet dat het geen waarden van de gebruiker kan lezen, zoals opdrachtregelargumenten. Als u toegang wilt krijgen tot opdrachtregelargumenten in Go, kunt u dit doen met het besturingssysteempakket en de os.Args variabele, die alle argumenten bevat die aan het programma zijn doorgegeven.

Met de volgende code worden twee getallen van de opdrachtregel gelezen en opgeteld:

package main

import (
    "fmt"
    "os"
    "strconv"
)

func main() {
    number1, _ := strconv.Atoi(os.Args[1])
    number2, _ := strconv.Atoi(os.Args[2])
    fmt.Println("Sum:", number1+number2)
}

De os.Args variabele bevat elk opdrachtregelargument dat aan het programma wordt doorgegeven. Omdat deze waarden van het type stringzijn, moet u ze converteren om int ze op te tellen.

Gebruik deze opdracht om het programma uit te voeren:

go run main.go 3 5

Dit is de uitvoer:

Sum: 8

Laten we eens kijken hoe we de bovenstaande code kunnen herstructureren en onze eerste aangepaste functie kunnen maken.

Aangepaste functies

Dit is de syntaxis voor het maken van een functie:

func name(parameters) (results) {
    body-content
}

U ziet dat u het func trefwoord gebruikt om een functie te definiëren en er vervolgens een naam aan toe te wijzen. Na de naam geeft u de lijst met parameters voor de functie op. Er kunnen nul of meer parameters zijn. U kunt ook de retourtypen van de functie definiëren, waarvan er ook nul of meer kunnen zijn. (In de volgende sectie wordt gesproken over het retourneren van meerdere waarden.) En nadat u al deze waarden hebt gedefinieerd, schrijft u de hoofdtekstinhoud van de functie.

Als u deze techniek wilt oefenen, gaan we de code van de vorige sectie herstructureren om de getallen in een aangepaste functie op te tellen. We gebruiken deze code:

package main

import (
    "fmt"
    "os"
    "strconv"
)

func main() {
    sum := sum(os.Args[1], os.Args[2])
    fmt.Println("Sum:", sum)
}

func sum(number1 string, number2 string) int {
    int1, _ := strconv.Atoi(number1)
    int2, _ := strconv.Atoi(number2)
    return int1 + int2
}

Met deze code wordt een functie sum gemaakt die twee string argumenten accepteert, naar deze verwijst inten vervolgens het resultaat van het optellen ervan retourneert. Wanneer u een retourtype definieert, moet uw functie een waarde van dat type retourneren.

In Go kunt u ook een naam instellen op de retourwaarde van een functie, alsof het een variabele is. U kunt de sum functie bijvoorbeeld als volgt herstructureren:

func sum(number1 string, number2 string) (result int) {
    int1, _ := strconv.Atoi(number1)
    int2, _ := strconv.Atoi(number2)
    result = int1 + int2
    return
}

U ziet dat u nu de resultaatwaarde van de functie tussen haakjes moet insluiten. U kunt ook de variabele in de functie gebruiken en gewoon een return lijn aan het einde toevoegen. Go retourneert de huidige waarden van deze retourvariabelen. De eenvoud van het schrijven van het return trefwoord aan het einde van de functie is aantrekkelijk (vooral wanneer er meer dan één retourwaarde is). We raden deze methode niet aan. Het kan onduidelijk zijn wat de functie retourneert.

Meerdere waarden retourneren

In Go kan een functie meer dan één waarde retourneren. U kunt deze waarden definiëren op een manier die vergelijkbaar is met de manier waarop u de parameters van de functie definieert. Met andere woorden, u geeft een type en een naam op, maar de naam is optioneel.

Stel dat u een functie wilt maken waarmee twee getallen worden opgeteld, maar die ook worden vermenigvuldigd. De functiecode ziet er als volgt uit:

func calc(number1 string, number2 string) (sum int, mul int) {
    int1, _ := strconv.Atoi(number1)
    int2, _ := strconv.Atoi(number2)
    sum = int1 + int2
    mul = int1 * int2
    return
}

U hebt nu twee variabelen nodig om de resultaten van de functie op te slaan. (Anders wordt het niet gecompileerd.) Dit ziet er als volgt uit:

package main

import (
    "fmt"
    "os"
    "strconv"
)

func main() {
    sum, mul := calc(os.Args[1], os.Args[2])
    fmt.Println("Sum:", sum)
    fmt.Println("Mul:", mul)
}

Een andere interessante functie in Go is dat als u geen van de retourwaarden van een functie nodig hebt, u deze kunt negeren door de retourwaarde toe te wijzen aan de _ variabele. De _ variabele is de idiomatische manier voor Go om retourwaarden te negeren. Hiermee kan het programma worden gecompileerd. Als u dus alleen de somwaarde wilt, kunt u deze code gebruiken:

package main

import (
    "fmt"
    "os"
    "strconv"
)

func main() {
    sum, _ := calc(os.Args[1], os.Args[2])
    fmt.Println("Sum:", sum)
}

We kijken meer naar het negeren van retourwaarden van functies wanneer we foutafhandeling in een toekomstige module verkennen.

Functieparameterwaarden wijzigen (aanwijzers)

Wanneer u een waarde doorgeeft aan een functie, heeft elke wijziging in die functie geen invloed op de aanroeper. Go is een programmeertaal 'pass by value'. Wanneer u een waarde doorgeeft aan een functie, neemt Go die waarde en maakt u een lokale kopie (een nieuwe variabele in het geheugen). Wijzigingen die u aanbrengt in die variabele in de functie, hebben geen invloed op de variabele die u naar de functie hebt verzonden.

Stel dat u een functie maakt om de naam van een persoon bij te werken. U ziet wat er gebeurt wanneer u deze code uitvoert:

package main

import "fmt"

func main() {
    firstName := "John"
    updateName(firstName)
    fmt.Println(firstName)
}

func updateName(name string) {
    name = "David"
}

Hoewel u de naam in de functie hebt gewijzigd in David, is de uitvoer nog steeds 'John'. De uitvoer is niet gewijzigd omdat de wijziging in de updateName functie alleen de lokale kopie wijzigt. Go heeft de waarde van de variabele doorgegeven, niet de variabele zelf.

Als u wilt dat de wijziging die u in de updateName functie aanbrengt, van invloed is op de firstName variabele in de main functie, moet u een aanwijzer gebruiken. Een aanwijzer is een variabele die het geheugenadres van een andere variabele bevat. Wanneer u een aanwijzer naar een functie verzendt, geeft u geen waarde door, u geeft een geheugenadres door. Elke wijziging die u in die variabele aanbrengt, is dus van invloed op de aanroeper.

In Go zijn er twee operators voor het werken met aanwijzers:

  • De & operator neemt het adres van het object dat erop volgt.
  • De * operator deducteert een aanwijzer. Hiermee krijgt u toegang tot het object op het adres in de aanwijzer.

Laten we ons vorige voorbeeld aanpassen om te verduidelijken hoe aanwijzers werken:

package main

import "fmt"

func main() {
    firstName := "John"
    updateName(&firstName)
    fmt.Println(firstName)
}

func updateName(name *string) {
    *name = "David"
}

Voer de voorgaande code uit. U ziet dat de uitvoer nu wordt weergegeven David in plaats van John.

Het eerste wat u moet doen, is de handtekening van de functie wijzigen om aan te geven dat u een aanwijzer wilt ontvangen. Hiervoor wijzigt u het parametertype van string in *string. (De laatste is nog steeds een tekenreeks, maar nu is het een aanwijzer naar een tekenreeks.) Wanneer u vervolgens een nieuwe waarde aan die variabele toewijst, moet u de ster (*) aan de linkerkant van de variabele toevoegen om de waarde van die variabele op te geven. Wanneer u de updateName functie aanroept, verzendt u de waarde niet, maar het geheugenadres van de variabele. Het & symbool aan de linkerkant van de variabele geeft het adres van de variabele aan.