"Si un ouvrier veut bien faire son travail, il doit d'abord affûter ses outils." - Confucius, "Les Entretiens de Confucius. Lu Linggong"
Page de garde > La programmation > Présentation de Do Notation dans le package Mo pour Golang

Présentation de Do Notation dans le package Mo pour Golang

Publié le 2024-08-15
Parcourir:709

Introducing Do Notation in the Mo Package for Golang

Qu’est-ce que la notation Do ?

La notation Do est un sucre syntaxique principalement utilisé dans les langages de programmation fonctionnels comme Haskell et Scala. Il simplifie l'enchaînement des opérations monadiques, rendant le code plus lisible et maintenable. En apportant cette fonctionnalité à Go, nous pouvons désormais écrire du code plus propre et plus expressif lorsque nous travaillons avec des monades.

Pourquoi faire de la notation ?

Lorsqu'il s'agit de monades, en particulier dans une logique métier complexe, le chaînage des opérations peut devenir fastidieux. La gestion des erreurs et la gestion des différents états conduisent souvent à des structures profondément imbriquées et difficiles à suivre. La notation Do résout ce problème en nous permettant d'écrire des opérations monadiques dans un style séquentiel, semblable à la programmation impérative, mais avec tous les avantages de la programmation fonctionnelle.

Comment ça marche dans le package Mo ?

Dans Go, implémenter la notation do n'était pas simple, mais j'ai réussi à y parvenir en utilisant la fonction Do. Voici un aperçu rapide de la façon dont vous pouvez l'utiliser avec un exemple :

package main

import (
    "errors"
    "fmt"
    "github.com/samber/mo"
)

func validateBooking(params map[string]string) mo.Result[map[string]string] {
    if params["guest"] != "" && params["roomType"] != "" {
        return mo.Ok(params)
    }
    return mo.Err[map[string]string](errors.New("validation failed"))
}

func createBooking(guest string) mo.Result[string] {
    if guest != "" {
        return mo.Ok("Booking Created for: "   guest)
    }
    return mo.Err[string](errors.New("booking creation failed"))
}

func assignRoom(booking string, roomType string) mo.Result[string] {
    if roomType != "" {
        return mo.Ok("Room Assigned: "   roomType   " for "   booking)
    }
    return mo.Err[string](errors.New("room assignment failed"))
}

// This could be a service package that performs the entire process
func bookRoom(params map[string]string) mo.Result[[]string] {
    return mo.Do(func() []string {
        // Validate booking parameters
        values := validateBooking(params).MustGet()

        // Create booking
        booking := createBooking(values["guest"]).MustGet()

        // Assign room
        room := assignRoom(booking, values["roomType"]).MustGet()

        // Return success with booking and room details
        return []string{booking, room}
    })
}

func main() {
    params := map[string]string{
        "guest":   "Foo",
        "roomType": "Suite",
    }

    result := bookRoom(params)
    if result.IsError() {
        fmt.Println("Error:", result.Error())
    } else {
        fmt.Println("Success:", result.MustGet())
    }
}

Dans cet exemple, bookRoom utilise la fonction Do pour effectuer séquentiellement plusieurs opérations : valider les paramètres de réservation, créer une réservation et attribuer une salle. Chaque étape renvoie un résultat qui peut être enchaîné de manière transparente à l'aide de la fonction Do, garantissant une gestion des erreurs propre et lisible.

Comparaison de la fonction bookRoom

Sans notation Do

Vous pouvez avoir deux options :

1. Utilisation de bind (si implémenté) :
L'opération de « liaison » dans les monades peut ressembler à l'enfer des rappels lorsqu'il existe de nombreuses opérations monadiques en raison de la nature imbriquée et séquentielle de ces opérations. Lorsque de nombreuses opérations de ce type sont enchaînées, le code peut devenir profondément imbriqué et plus difficile à lire, de la même manière que les rappels peuvent être profondément imbriqués dans la programmation asynchrone. Si bind était implémenté dans le package Mo, son utilisation dans cet exemple ressemblerait à ceci :

func bookRoom(params map[string]string) mo.Result[[]string] {
    return bind(validateBooking(params), func(values map[string]string) mo.Result[[]string] {
        return bind(createBooking(values["guest"]), func(booking string) mo.Result[[]string] {
            return bind(assignRoom(booking, values["roomType"]), func(room string) mo.Result[[]string] {
                return mo.Ok([]string{booking, room})
            })
        })
    })
}

Cette approche devient rapidement difficile à lire et à maintenir.

2. Utilisation de .Get() :
Une autre option consiste à utiliser .Get() sur la monade pour déballer la monade et obtenir la valeur et l'erreur sous-jacentes. Cela ressemble à du code Go typique, mais la gestion des erreurs peut être verbeuse :

func bookRoom(params map[string]string) mo.Result[[]string] {
    values, err := validateBooking(params).Get()
    if err != nil {
        return mo.Err[[]string](err)
    }

    booking, err := createBooking(values["guest"]).Get()
    if err != nil {
        return mo.Err[[]string](err)
    }

    room, err := assignRoom(booking, values["roomType"]).Get()
    if err != nil {
        return mo.Err[[]string](err)
    }

    return mo.Ok([]string{booking, room})
}

Cette approche est plus lisible que l'utilisation de bind, mais implique toujours beaucoup de gestion des erreurs passe-partout.

Avec Do-Notation

Avec la notation do, vous pouvez appeler .MustGet() sur la monade pour obtenir la valeur sous-jacente directement sans erreur. Cette fonction (MustGet()) paniquera si la monade a une erreur ; cependant, la notation do gérera cela et court-circuitera l'exécution s'il y a une erreur ou renverra la valeur non enveloppée :

func bookRoom(params map[string]string) mo.Result[[]string] {
    return mo.Do(func() []string {
        values := validateBooking(params).MustGet()
        booking := createBooking(values["guest"]).MustGet()
        room := assignRoom(booking, values["roomType"]).MustGet()
        return []string{booking, room}
    })
}

Cette approche est claire, concise et facile à lire, réduisant considérablement le code standard de gestion des erreurs.


Pensées finales

L'un des grands avantages de l'utilisation de la notation do est que vous n'avez pas besoin de vérifier les erreurs après chaque opération monadique. Même si une monade peut avoir un type d'erreur, la notation do gérera automatiquement la propagation des erreurs et court-circuitera l'exécution si une erreur se produit. Cela conduit à un code plus propre et plus maintenable, ce qui est particulièrement précieux dans les flux de travail complexes.

Déclaration de sortie Cet article est reproduit sur : https://dev.to/taman9333/introducing-do-notation-in-the-mo-package-for-golang-1jpc?1 En cas de violation, veuillez contacter [email protected] pour le supprimer
Dernier tutoriel Plus>

Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.

Copyright© 2022 湘ICP备2022001581号-3