「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > Golang の Mo パッケージに Do 記法を導入

Golang の Mo パッケージに Do 記法を導入

2024 年 8 月 15 日に公開
ブラウズ:117

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 関数を使用してシームレスに連鎖できる Result を返し、クリーンで読みやすいエラー処理を保証します。

bookRoom機能比較

Do 表記なし

2 つのオプションがあります:

1.バインドの使用 (実装されている場合):
モナドの「バインド」操作は、多数のモナド操作がある場合、これらの操作のネストされた順次的な性質のため、コールバック地獄に似ている可能性があります。このような操作が多数連鎖すると、非同期プログラミングでコールバックが深くネストされるのと同様に、コードが深くネストされ、読みにくくなる可能性があります。 Bind が 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():
の使用 もう 1 つのオプションは、モナドで .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 記法を使用する大きな利点の 1 つは、モナド演算のたびにエラーをチェックする必要がないことです。モナドはエラー型を持つことができますが、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