Programmation fonctionnelle en Go : principes et exemples

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Programmation fonctionnelle en Go : de l'impératif au déclaratif



Go (Golang) est traditionnellement associé à la programmation impérative et concurrente, mais son puissant système de types et son support des fonctions de première classe rendent possible l'application de nombreux principes de la programmation fonctionnelle (PF). Dans cet article, nous allons voir comment appliquer les idiomes de la PF en Go, sans sacrifier les performances ni la lisibilité du code.



Principes fondamentaux de la PF dans le contexte de Go



La programmation fonctionnelle en Go ne signifie pas un rejet total de l'état mutable. Nous utilisons plutôt les concepts suivants :



  • Fonctions pures — des fonctions dont le résultat ne dépend que des arguments, sans effets secondaires.
  • Immutabilité (Immutability) — la préférence pour la création de nouvelles structures de données plutôt que la modification de celles existantes.
  • Fonctions d'ordre supérieur — des fonctions qui prennent d'autres fonctions comme arguments ou les retournent.
  • Fermetures (Closures) — des fonctions qui capturent des variables de la portée externe.


Fonctions d'ordre supérieur : map, filter, reduce



Go n'a pas de génériques intégrés (avant la version 1.18), donc les classiques map, filter, reduce sont implémentés via des interfaces ou une copie explicite. Regardons un exemple avec des nombres entiers :



package main

import "fmt"

// Map — applique une fonction à chaque élément d'une slicefunc Map(s []int, fn func(int) int) []int { result := make([]int, len(s)) for i, v := range s { result[i] = fn(v) } return result}

// Filter — ne conserve que les éléments satisfaisant la conditionfunc Filter(s []int, fn func(int) bool) []int { var result []int for _, v := range s { if fn(v) { result = append(result, v) } } return result}

// Reduce — réduit une slice à une seule valeurfunc Reduce(s []int, init int, fn func(int, int) int) int { acc := init for _, v := range s { acc = fn(acc, v) } return acc}

func main() { nums := []int{1, 2, 3, 4, 5}

// Double chaque élément doubled := Map(nums, func(x int) int { return x * 2 }) fmt.Println("Map:", doubled) // [2 4 6 8 10]

// Ne conserve que les pairs evens := Filter(nums, func(x int) bool { return x%2 == 0 }) fmt.Println("Filter:", evens) // [2 4]

// Additionne tous les éléments sum := Reduce(nums, 0, func(acc, x int) int { return acc + x }) fmt.Println("Reduce:", sum) // 15}


Important : Avec les génériques dans Go 1.18+, on peut créer des versions universelles :



// Generic Mapfunc MapGeneric[T, U any](s []T, fn func(T) U) []U {    result := make([]U, len(s))    for i, v := range s {        result[i] = fn(v)    }    return result}


Fermetures et curryfication en Go



Les fermetures en Go sont un outil puissant pour créer des fonctions avec conservation d'état. Regardons un exemple de générateur de séquence :



package main

import "fmt"

// Générateur de séquence de Fibonaccifunc fibonacci() func() int { a, b := 0, 1 return func() int { a, b = b, a+b return a }}

// Curryfication : fonction qui prend des arguments par étapesfunc add(a int) func(int) int { return func(b int) int { return a + b }}

func main() { fib := fibonacci() fmt.Println(fib()) // 1 fmt.Println(fib()) // 1 fmt.Println(fib()) // 2

// Curryfication add5 := add(5) fmt.Println(add5(10)) // 15 fmt.Println(add5(20)) // 25}


Les fermetures sont particulièrement utiles pour :

  • Créer des fonctions configurables (middleware)
  • Implémenter le pattern "fabrique de fonctions"
  • Organiser des mécanismes de callback


Immutabilité

Blogs

Book Recommendations