"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Apresentando a notação Do no pacote Mo para Golang

Apresentando a notação Do no pacote Mo para Golang

Publicado em 15/08/2024
Navegar:417

Introducing Do Notation in the Mo Package for Golang

O que é notação?

A notação Do é um açúcar sintático usado principalmente em linguagens de programação funcionais como Haskell e Scala. Simplifica o encadeamento de operações monádicas, tornando o código mais legível e de fácil manutenção. Ao trazer esse recurso para Go, agora podemos escrever código mais limpo e expressivo ao trabalhar com mônadas.

Por que fazer notação?

Ao lidar com mônadas, especialmente em lógicas de negócios complexas, as operações de encadeamento podem se tornar complicadas. O tratamento de erros e o gerenciamento de diferentes estados geralmente levam a estruturas profundamente aninhadas que são difíceis de seguir. A notação Do resolve isso, permitindo-nos escrever operações monádicas em um estilo sequencial, semelhante à programação imperativa, mas com todos os benefícios da programação funcional.

Como funciona no pacote Mo?

Em Go, implementar a notação do não foi simples, mas consegui fazê-lo usando a função Do. Aqui está uma rápida olhada em como você pode usá-lo com um exemplo:

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())
    }
}

Neste exemplo, bookRoom usa a função Do para realizar diversas operações sequencialmente: validar parâmetros de reserva, criar uma reserva e atribuir um quarto. Cada etapa retorna um resultado que pode ser perfeitamente encadeado usando a função Do, garantindo um tratamento de erros limpo e legível.

Comparação da função bookRoom

Sem notação de execução

Você pode ter duas opções:

1. Usando bind (se implementado):
A operação "bind" em mônadas pode se assemelhar ao inferno de retorno de chamada quando há muitas operações monádicas devido à natureza aninhada e sequencial dessas operações. Quando muitas dessas operações são encadeadas, o código pode ficar profundamente aninhado e mais difícil de ler, semelhante à profundidade dos retornos de chamada na programação assíncrona. Se o bind fosse implementado no pacote Mo, usá-lo neste exemplo seria algo assim:

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})
            })
        })
    })
}

Essa abordagem rapidamente se torna difícil de ler e manter.

2. Usando .Get():
Outra opção é usar .Get() na mônada para desembrulhar a mônada e obter o valor e o erro subjacentes. Parece um código Go típico, mas o tratamento de erros pode ser detalhado:

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})
}

Essa abordagem é mais legível do que usar bind, mas ainda envolve muito tratamento de erros padrão.

Com notação Do

Com a notação do, você pode chamar .MustGet() na mônada para obter o valor subjacente diretamente sem erros. Esta função (MustGet()) entrará em pânico se a mônada apresentar um erro; no entanto, a notação irá lidar com isso e causar um curto-circuito na execução se houver um erro ou retornar o valor desembrulhado:

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}
    })
}

Essa abordagem é limpa, concisa e fácil de ler, reduzindo significativamente o código padrão de tratamento de erros.


Considerações Finais

Uma das grandes vantagens de usar a notação do é que você não precisa verificar se há erros após cada operação monádica. Mesmo que uma mônada possa ter um tipo de erro, a notação tratará automaticamente a propagação do erro e causará um curto-circuito na execução se ocorrer um erro. Isso leva a um código mais limpo e de fácil manutenção, o que é particularmente valioso em fluxos de trabalho complexos.

Declaração de lançamento Este artigo foi reproduzido em: https://dev.to/taman9333/introduzindo-do-notation-in-the-mo-package-for-golang-1jpc?1 Se houver alguma violação, entre em contato com [email protected] para excluí-lo
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3