Les fonctions en Go

Apprenez à écrire des fonctions en Go : paramètres et retours typés, retours multiples et nommés, fonctions variadiques, closures et la convention result-error.

Prérequis

Objectifs pédagogiques

  • Déclarer des fonctions avec paramètres et retours typés
  • Retourner plusieurs valeurs et suivre la convention result-error
  • Utiliser les fonctions variadiques et les closures à bon escient

Une fonction regroupe une logique réutilisable derrière un nom. Vous la déclarez avec le mot-clé func, listez ses paramètres typés et indiquez les types qu’elle retourne. Les fonctions sont la principale unité de réutilisation en Go, et ce sont aussi des valeurs.

Déclarer une fonction

La liste des paramètres vient d’abord, puis le type de retour, puis le corps. Utilisez return pour renvoyer une valeur.

func greet(name string) string {
	return "Bonjour, " + name
}

Lorsque plusieurs paramètres partagent un type, écrivez le type une seule fois à la fin :

func add(a, b int) int {
	return a + b
}

Les retours multiples

Une fonction Go peut retourner plusieurs valeurs. C’est utilisé en permanence, le plus souvent pour renvoyer un résultat accompagné d’un état.

func minMax(a, b int) (int, int) {
	if a < b {
		return a, b
	}
	return b, a
}

L’appelant reçoit les deux valeurs en un seul appel : lo, hi := minMax(9, 4).

Les retours nommés (avec parcimonie)

Vous pouvez nommer les valeurs de retour. Elles se comportent comme des variables initialisées à leur valeur zéro, et un return nu renvoie leurs valeurs courantes.

func split(sum int) (x, y int) {
	x = sum * 4 / 9
	y = sum - x
	return
}

Les retours nommés peuvent documenter l’intention, mais un return nu dans une longue fonction se lit mal. Préférez des retours explicites, sauf si les noms apportent vraiment de la clarté.

Les fonctions variadiques

Un dernier paramètre écrit ...T accepte un nombre quelconque d’arguments, qui arrivent sous forme de slice.

func sum(nums ...int) int {
	total := 0
	for _, n := range nums {
		total += n
	}
	return total
}

Appelez-la avec sum(1, 2, 3), ou déployez une slice existante avec sum(values...).

Les fonctions comme valeurs et les closures

Les fonctions sont des valeurs de première classe : vous pouvez les stocker dans des variables et les retourner. Une fonction qui capture des variables de son environnement est une closure.

func counter() func() int {
	count := 0
	return func() int {
		count++
		return count
	}
}

Chaque appel à counter() renvoie une nouvelle fonction avec son propre count privé.

La convention result-error

Le Go idiomatique signale un échec en retournant une valeur et une error. Par convention, l’error est la dernière valeur de retour et vaut nil en cas de succès. L’appelant la vérifie avant d’utiliser le résultat.

package main

import (
	"errors"
	"fmt"
)

// divide retourne le quotient entier de a par b.
// Elle retourne une erreur lorsque b vaut zéro.
func divide(a, b int) (int, error) {
	if b == 0 {
		return 0, errors.New("division par zéro")
	}
	return a / b, nil
}

func main() {
	if q, err := divide(10, 2); err == nil {
		fmt.Println("10 / 2 =", q)
	}

	if _, err := divide(1, 0); err != nil {
		fmt.Println("erreur :", err)
	}
}

Son exécution affiche :

10 / 2 = 5
erreur : division par zéro

Erreurs fréquentes

  • Ignorer l’erreur retournée. Si une fonction retourne (T, error), vérifiez l’error ; ne l’ignorez avec _ que si vous êtes certain qu’elle ne peut pas survenir.
  • Retourner une valeur utile avec une erreur non nulle. En cas d’échec, retournez la valeur zéro pour que l’appelant ne soit pas tenté d’utiliser un résultat invalide.
  • Abuser des retours nommés. Dans une longue fonction, un return nu cache ce qui est réellement renvoyé. Ne nommez les retours que si cela améliore la clarté.

À vous de jouer

Écrivez une fonction average(nums ...float64) float64 qui retourne la moyenne de ses arguments, et 0 si elle est appelée sans argument. Affichez la moyenne de 4, 8, 15, 16, 23, 42 avec deux décimales.

Afficher la correction
package main

import "fmt"

func average(nums ...float64) float64 {
	if len(nums) == 0 {
		return 0
	}
	var sum float64
	for _, n := range nums {
		sum += n
	}
	return sum / float64(len(nums))
}

func main() {
	fmt.Printf("%.2f\n", average(4, 8, 15, 16, 23, 42))
}

Le garde-fou sur le cas vide évite une division par zéro, et diviser la somme par le nombre d’éléments donne 18.00.

Résumé

  • Déclarez les fonctions avec func, des paramètres typés et des retours typés.
  • Les retours multiples portent la convention (result, error).
  • Les paramètres variadiques et les closures rendent les fonctions flexibles ; gardez-les courtes.

Ensuite, explorez l’idiome qui façonne les API Go avec la gestion des erreurs, et revenez sur la manière de stocker des valeurs dans les variables et types.

Votre progression est enregistrée uniquement dans ce navigateur. Aucun compte n’est requis.

Recherche

La recherche s’exécute entièrement dans votre navigateur.