”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 在 Golang 的 Mo 包中引入 Do 表示法

在 Golang 的 Mo 包中引入 Do 表示法

发布于2024-08-15
浏览:841

Introducing Do Notation in the Mo Package for Golang

什么是 Do 表示法?

Do 表示法是一种语法糖,主要用于 Haskell 和 Scala 等函数式编程语言。它简化了单子操作的链接,使代码更具可读性和可维护性。通过将此功能引入 Go,我们现在可以在使用 monad 时编写更清晰、更具表现力的代码。

为什么要做记号?

在处理 monad 时,尤其是在复杂的业务逻辑中,链接操作可能会变得很麻烦。错误处理和管理不同的状态通常会导致难以理解的深层嵌套结构。 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 函数无缝链接该结果,确保干净且可读的错误处理。

书房功能比较

没有 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():
另一种选择是在 monad 上使用 .Get() 来打开 monad 并获取底层值和错误。这看起来像典型的 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 表示法,您可以在 monad 上调用 .MustGet() 来直接获取底层值,不会出现错误。如果 monad 出现错误,该函数(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 表示法的一大优点是您不必在每次单子操作后检查错误。即使 monad 可以有错误类型,如果发生错误,do 表示法将自动处理错误传播并短路执行。这会带来更干净、更易于维护的代码,这在复杂的工作流程中特别有价值。

版本声明 本文转载于:https://dev.to/taman9333/introducing-do-notation-in-the-mo-package-for-golang-1jpc?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 如何高效地在一个事务中插入数据到多个MySQL表?
    如何高效地在一个事务中插入数据到多个MySQL表?
    mySQL插入到多个表中,该数据可能会产生意外的结果。虽然似乎有多个查询可以解决问题,但将从用户表的自动信息ID与配置文件表的手动用户ID相关联提出了挑战。使用Transactions和last_insert_id() 插入用户(用户名,密码)值('test','test...
    编程 发布于2025-05-25
  • Python读取CSV文件UnicodeDecodeError终极解决方法
    Python读取CSV文件UnicodeDecodeError终极解决方法
    在试图使用已内置的CSV模块读取Python中时,CSV文件中的Unicode Decode Decode Decode Decode decode Error读取,您可能会遇到错误的错误:无法解码字节 在位置2-3中:截断\ uxxxxxxxx逃脱当CSV文件包含特殊字符或Unicode的路径逃...
    编程 发布于2025-05-25
  • 如何使用Python有效地以相反顺序读取大型文件?
    如何使用Python有效地以相反顺序读取大型文件?
    在python 中,如果您使用一个大文件,并且需要从最后一行读取其内容,则在第一行到第一行,Python的内置功能可能不合适。这是解决此任务的有效解决方案:反向行读取器生成器 == ord('\ n'): 缓冲区=缓冲区[:-1] ...
    编程 发布于2025-05-25
  • 如何简化PHP中的JSON解析以获取多维阵列?
    如何简化PHP中的JSON解析以获取多维阵列?
    php 试图在PHP中解析JSON数据的JSON可能具有挑战性,尤其是在处理多维数组时。要简化过程,建议将JSON作为数组而不是对象解析。执行此操作,将JSON_DECODE函数与第二个参数设置为true:[&&&&& && &&&&& json = JSON = JSON_DECODE($ j...
    编程 发布于2025-05-25
  • PHP与C++函数重载处理的区别
    PHP与C++函数重载处理的区别
    作为经验丰富的C开发人员脱离谜题,您可能会遇到功能超载的概念。这个概念虽然在C中普遍,但在PHP中构成了独特的挑战。让我们深入研究PHP功能过载的复杂性,并探索其提供的可能性。在PHP中理解php的方法在PHP中,函数超载的概念(如C等语言)不存在。函数签名仅由其名称定义,而与他们的参数列表无关。...
    编程 发布于2025-05-25
  • 在PHP中如何高效检测空数组?
    在PHP中如何高效检测空数组?
    在PHP 中检查一个空数组可以通过各种方法在PHP中确定一个空数组。如果需要验证任何数组元素的存在,则PHP的松散键入允许对数组本身进行直接评估:一种更严格的方法涉及使用count()函数: if(count(count($ playerList)=== 0){ //列表为空。 } 对...
    编程 发布于2025-05-25
  • 用户本地时间格式及时区偏移显示指南
    用户本地时间格式及时区偏移显示指南
    在用户的语言环境格式中显示日期/时间,并使用时间偏移在向最终用户展示日期和时间时,以其localzone and格式显示它们至关重要。这确保了不同地理位置的清晰度和无缝用户体验。以下是使用JavaScript实现此目的的方法。方法:推荐方法是处理客户端的Javascript中的日期/时间格式化和时...
    编程 发布于2025-05-25
  • 如何将来自三个MySQL表的数据组合到新表中?
    如何将来自三个MySQL表的数据组合到新表中?
    mysql:从三个表和列的新表创建新表 答案:为了实现这一目标,您可以利用一个3-way Join。 选择p。*,d.content作为年龄 来自人为p的人 加入d.person_id = p.id上的d的详细信息 加入T.Id = d.detail_id的分类法 其中t.taxonomy =...
    编程 发布于2025-05-25
  • 版本5.6.5之前,使用current_timestamp与时间戳列的current_timestamp与时间戳列有什么限制?
    版本5.6.5之前,使用current_timestamp与时间戳列的current_timestamp与时间戳列有什么限制?
    在时间戳列上使用current_timestamp或MySQL版本中的current_timestamp或在5.6.5 此限制源于遗留实现的关注,这些限制需要对当前的_timestamp功能进行特定的实现。 创建表`foo`( `Productid` int(10)unsigned not n...
    编程 发布于2025-05-25
  • `console.log`显示修改后对象值异常的原因
    `console.log`显示修改后对象值异常的原因
    foo = [{id:1},{id:2},{id:3},{id:4},{id:id:5},],]; console.log('foo1',foo,foo.length); foo.splice(2,1); console.log('foo2', foo, foo....
    编程 发布于2025-05-25
  • MySQL中如何高效地根据两个条件INSERT或UPDATE行?
    MySQL中如何高效地根据两个条件INSERT或UPDATE行?
    在两个条件下插入或更新或更新 solution:的答案在于mysql的插入中...在重复键更新语法上。如果不存在匹配行或更新现有行,则此功能强大的功能可以通过插入新行来进行有效的数据操作。如果违反了唯一的密钥约束。实现所需的行为,该表必须具有唯一的键定义(在这种情况下为'名称'...
    编程 发布于2025-05-25
  • 如何使用PHP将斑点(图像)正确插入MySQL?
    如何使用PHP将斑点(图像)正确插入MySQL?
    essue VALUES('$this->image_id','file_get_contents($tmp_image)')";This code builds a string in PHP, but the function call ...
    编程 发布于2025-05-25
  • 如何从PHP中的Unicode字符串中有效地产生对URL友好的sl。
    如何从PHP中的Unicode字符串中有效地产生对URL友好的sl。
    为有效的slug生成首先,该函数用指定的分隔符替换所有非字母或数字字符。此步骤可确保slug遵守URL惯例。随后,它采用ICONV函数将文本简化为us-ascii兼容格式,从而允许更广泛的字符集合兼容性。接下来,该函数使用正则表达式删除了不需要的字符,例如特殊字符和空格。此步骤可确保slug仅包含...
    编程 发布于2025-05-25
  • 如何使用替换指令在GO MOD中解析模块路径差异?
    如何使用替换指令在GO MOD中解析模块路径差异?
    在使用GO MOD时,在GO MOD 中克服模块路径差异时,可能会遇到冲突,其中可能会遇到一个冲突,其中3派对软件包将另一个带有导入套件的path package the Imptioned package the Imptioned package the Imported tocted pac...
    编程 发布于2025-05-25

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3