«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Представляем нотацию Do в пакете Mo для Golang

Представляем нотацию Do в пакете Mo для Golang

Опубликовано 15 августа 2024 г.
Просматривать:882

Introducing Do Notation in the Mo Package for Golang

Что такое нотация Do?

Нотация Do — это синтаксический сахар, который в основном используется в языках функционального программирования, таких как Haskell и Scala. Это упрощает цепочку монадических операций, делая код более читабельным и удобным в сопровождении. Внеся эту функцию в Go, мы теперь можем писать более чистый и выразительный код при работе с монадами.

Зачем делать обозначения?

При работе с монадами, особенно в сложной бизнес-логике, операции объединения в цепочки могут стать громоздкими. Обработка ошибок и управление различными состояниями часто приводят к глубоко вложенным структурам, за которыми трудно следить. Нотация Do решает эту проблему, позволяя нам писать монадические операции в последовательном стиле, похожем на императивное программирование, но со всеми преимуществами функционального программирования.

Как это работает в пакете Mo?

В Go реализовать нотацию do было непросто, но мне удалось добиться этого с помощью функции Do. Вот краткий обзор того, как вы можете использовать его на примере:

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

В этом примере bookRoom использует функцию Do для последовательного выполнения нескольких операций: проверки параметров бронирования, создания бронирования и назначения комнаты. Каждый шаг возвращает результат, который можно легко связать с помощью функции Do, обеспечивая четкую и читаемую обработку ошибок.

Сравнение функции bookRoom

Без Do-нотации

Вы можете выбрать два варианта:

1. Использование привязки (если реализовано):
Операция «связывания» в монадах может напоминать ад обратных вызовов, когда монадических операций много, из-за вложенного и последовательного характера этих операций. Когда множество таких операций объединены в цепочку, код может стать глубоко вложенным и трудным для чтения, подобно тому, насколько глубоко вложенными могут быть обратные вызовы в асинхронном программировании. Если бы привязка была реализована в пакете Mo, ее использование в этом примере выглядело бы примерно так:

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

Такой подход быстро становится трудным для чтения и поддержки.

2. Использование .Get():
Другой вариант — использовать .Get() для монады, чтобы развернуть монаду и получить базовое значение и ошибку. Это похоже на типичный код Go, но обработка ошибок может быть многословной:

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

Этот подход более удобен для чтения, чем использование связывания, но все же требует большого количества шаблонной обработки ошибок.

С Do-нотацией

С помощью нотации do вы можете вызвать .MustGet() для монады, чтобы получить базовое значение напрямую без ошибок. Эта функция (MustGet()) вызовет панику, если в монаде возникнет ошибка; однако нотация do обработает это и замкнет выполнение в случае ошибки или вернет развернутое значение обратно:

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

Этот подход понятен, лаконичен и легко читается, что значительно сокращает количество шаблонного кода обработки ошибок.


Заключительные мысли

Одним из больших преимуществ использования нотации do является то, что вам не нужно проверять наличие ошибок после каждой монадической операции. Несмотря на то, что монада может иметь тип ошибки, нотация do будет автоматически обрабатывать распространение ошибок и сокращать выполнение в случае возникновения ошибки. Это приводит к более чистому и удобному в сопровождении коду, что особенно ценно в сложных рабочих процессах.

Заявление о выпуске Эта статья воспроизведена по адресу: https://dev.to/taman9333/introducing-do-notation-in-the-mo-package-for-golang-1jpc?1 Если есть какие-либо нарушения, пожалуйста, свяжитесь с [email protected] удалить его
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3