当前位置:   article > 正文

golang 函数式编程库samber/mo使用: Either

golang 函数式编程库samber/mo使用: Either

golang 函数式编程库samber/mo使用: Either

如果您不了解samber/mo库, 请先阅读第一篇 Option

结构定义

有时候我们不确定值的类型, 一个值可能是int, 也可能是string, 这时候我们可以使用Either类型。 Either类型是一种表示两种可能值的类型, 和python中的 Optional类似。 结构定义如下:

type Either[L any, R any] struct {
	isLeft bool

	left  L
	right R
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

其中 isLeft表示值的类型, left和right分别表示两种可能的值。 如果isLeft为true, 则left有值, right为nil; 如果isLeft为false, 则right有值, left为nil。

构造函数

主要有一下两个:

  • mo.Left() 函数定义func Left[L any, R any](value L) Either[L, R] L, R分别表示两种可能的值的类型, value表示左值。 doc

  • mo.Right() 和Left类似 doc

使用示例

Either类型最常见的用法是处理错误, 正好适用于go语言。 因为go语言没有提供 try...catch 语法, 优点是错误显式处理,可以避免忘记捕获异常, 缺点是代码不够优雅。

举个例子, 如果我们用go自带的error处理, 代码如下:

package main

import (
	"errors"
	"fmt"
)

var (
	ErrRedisNotFound = errors.New("redis not found")
	ErrDBNotFound    = errors.New("db not found")
)

func readFromRedis() (string, error) {
	// let's simulate a failed operation
	return "", ErrRedisNotFound
}

func readFromDB() (string, error) {
	// let's simulate a successful operation
	return "user:1:Samber", nil
}

func main() {
	data, err := readFromRedis()
	if err != nil {
		fmt.Println("redis not found, read from db")
		data, err = readFromDB()
		if err != nil {
			fmt.Println("db not found")
		} else {
			fmt.Println("data from db is:", data)
		}
	} else {
		fmt.Println("data from redis", data)
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

可以看到里面充满了if else, 代码中的逻辑结构表达得不够清晰。 使用Either处理错误的代码如下:

package main

import (
	"errors"
	"fmt"

	"github.com/samber/mo"
)

var (
	ErrRedisNotFound = errors.New("redis not found")
	ErrDBNotFound    = errors.New("db not found")
)

func readFromRedis() mo.Either[string, error] {
	// let's simulate a failed operation
	return mo.Right[string, error](ErrRedisNotFound)
}

func readFromDB() mo.Either[string, error] {
	// let's simulate a success operation
	return mo.Left[string, error]("user:1:Samber")
}

func main() {
	readFromRedis().
        Match(
			func(data string) mo.Either[string, error] {
				fmt.Println("data from redis", data)
				return mo.Left[string, error](data)
			},
			func(err error) mo.Either[string, error] {
				fmt.Println("redis not found, read from db")
				return readFromDB().
					Match(
						func(data string) mo.Either[string, error] {
							fmt.Println("data from db is:", data)
							return mo.Left[string, error](data)
						},
						func(err error) mo.Either[string, error] {
							fmt.Println("db not found")
							return mo.Right[string, error](err)
						},
					)
			},
		)
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

代码虽然更长了,但是逻辑结构很清晰

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/164080
推荐阅读
相关标签
  

闽ICP备14008679号