golang基于泛型的函数式编程抽象插件库mo的使用

Golang基于泛型的函数式编程抽象插件库mo的使用

mo是一个为Go项目带来Monad和流行函数式编程抽象的库,它利用了Go 1.18+的泛型特性。

安装

go get github.com/samber/mo@v1

快速开始

导入mo库:

import (
    "github.com/samber/mo"
)

主要特性

mo库支持以下数据类型:

  • Option[T] (Maybe)
  • Result[T]
  • Either[A, B]
  • EitherX[T1, ..., TX] (X在3到5之间)
  • Future[T]
  • IO[T]
  • IOEither[T]
  • Task[T]
  • TaskEither[T]
  • State[S, A]

示例代码

Option[T] 示例

option1 := mo.Some(42)
// Some(42)

option1.
    FlatMap(func (value int) mo.Option[int] {
        return mo.Some(value*2)
    }).
    FlatMap(func (value int) mo.Option[int] {
        return mo.Some(value%2)
    }).
    FlatMap(func (value int) mo.Option[int] {
        return mo.Some(value+21)
    }).
    OrElse(1234)
// 21

option2 := mo.None[int]()
// None

option2.OrElse(1234)
// 1234

option3 := option1.Match(
    func(i int) (int, bool) {
        // 当值存在时
        return i * 2, true
    },
    func() (int, bool) {
        // 当值不存在时
        return 0, false
    },
)
// Some(42)

Result[T] 示例

result1 := mo.Ok(42)
// Ok(42)

result2 := mo.Err[int](errors.New("something went wrong"))
// Err(something went wrong)

result3 := result1.Map(func(i int) int {
    return i * 2
})
// Ok(84)

result4 := result2.MapErr(func(err error) error {
    return fmt.Errorf("wrapped: %w", err)
})
// Err(wrapped: something went wrong)

Either[A, B] 示例

either1 := mo.Left[string, int]("error")
// Left(error)

either2 := mo.Right[string, int](42)
// Right(42)

either3 := either2.MapRight(func(i int) int {
    return i * 2
})
// Right(84)

either4 := either1.MapLeft(func(s string) string {
    return "prefix: " + s
})
// Left(prefix: error)

Future[T] 示例

future := mo.NewFuture(func(resolve func(int), reject func(error)) {
    // 模拟异步操作
    time.Sleep(100 * time.Millisecond)
    resolve(42)
})

future.Then(func(value int) mo.Result[int] {
    fmt.Println("Got value:", value)
    return mo.Ok(value * 2)
}).Catch(func(err error) mo.Result[int] {
    fmt.Println("Got error:", err)
    return mo.Err[int](err)
})

IO[T] 示例

io := mo.NewIO(func() int {
    fmt.Println("Running IO operation")
    return 42
})

result := io.Run()
fmt.Println("Result:", result)
// 输出:
// Running IO operation
// Result: 42

Task[T] 示例

task := mo.NewTask(func() int {
    fmt.Println("Running async task")
    return 42
})

future := task.Run()
result := future.Collect()
fmt.Println("Result:", result.MustGet())
// 输出:
// Running async task
// Result: 42

State[S, A] 示例

state := mo.NewState(func(s int) (int, int) {
    return s * 2, s + 1
})

value, newState := state.Run(5)
fmt.Println("Value:", value)      // 10
fmt.Println("New state:", newState) // 6

为什么选择mo?

  • 提供了函数式编程的常见抽象
  • 完全类型安全,利用Go 1.18+泛型
  • 无依赖,仅使用标准库
  • 简洁直观的API设计

mo库为Go开发者提供了函数式编程的强大工具,特别是在处理可选值、错误处理和异步操作时特别有用。


更多关于golang基于泛型的函数式编程抽象插件库mo的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang基于泛型的函数式编程抽象插件库mo的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用 mo 库进行 Golang 函数式编程

mo 是一个基于泛型的 Golang 函数式编程抽象插件库,它提供了许多实用的函数式编程工具,可以帮助你编写更简洁、更表达性的代码。

安装 mo

go get github.com/samber/mo

核心概念和功能

1. Option 类型

Option 类型用于处理可能存在或不存在的值,替代 nil 检查。

package main

import (
	"fmt"
	"github.com/samber/mo"
)

func getUserName(id int) mo.Option[string] {
	if id == 1 {
		return mo.Some("Alice")
	}
	return mo.None[string]()
}

func main() {
	name := getUserName(1)
	fmt.Println(name.OrElse("Unknown")) // 输出: Alice

	name = getUserName(2)
	fmt.Println(name.OrElse("Unknown")) // 输出: Unknown
}

2. Either 类型

Either 类型表示两种可能的值之一,通常用于错误处理。

func divide(a, b int) mo.Either[string, int] {
	if b == 0 {
		return mo.Left[string, int]("division by zero")
	}
	return mo.Right[string, int](a / b)
}

func main() {
	result := divide(10, 2)
	result.Match(
		func(err string) { fmt.Println("Error:", err) },
		func(val int) { fmt.Println("Result:", val) },
	) // 输出: Result: 5

	result = divide(10, 0)
	result.Match(
		func(err string) { fmt.Println("Error:", err) },
		func(val int) { fmt.Println("Result:", val) },
	) // 输出: Error: division by zero
}

3. Future 异步处理

mo 提供了 Future 类型来处理异步操作。

func asyncTask() mo.Future[int] {
	return mo.NewFuture(func(resolve func(int), reject func(error)) {
		// 模拟异步任务
		go func() {
			resolve(42)
		}()
	})
}

func main() {
	future := asyncTask()
	
	result := future.Collect()
	fmt.Println(result.MustGet()) // 输出: 42
}

4. 函数式组合

mo 提供了函数式组合工具。

func addOne(x int) int { return x + 1 }
func double(x int) int { return x * 2 }

func main() {
	// 函数组合
	composed := mo.Compose(addOne, double)
	fmt.Println(composed(5)) // (5+1)*2 = 12

	// 管道操作
	pipe := mo.Pipe(
		mo.NewOption(5),
		mo.Map(addOne),
		mo.Map(double),
	)
	fmt.Println(pipe.OrElse(0)) // 12
}

5. 集合操作

mo 提供了对切片和映射的函数式操作。

func main() {
	numbers := []int{1, 2, 3, 4, 5}

	// Map
	doubled := mo.MapSlice(numbers, func(x int) int { return x * 2 })
	fmt.Println(doubled) // [2 4 6 8 10]

	// Filter
	evens := mo.FilterSlice(numbers, func(x int) bool { return x%2 == 0 })
	fmt.Println(evens) // [2 4]

	// Reduce
	sum := mo.ReduceSlice(numbers, 0, func(acc, x int) int { return acc + x })
	fmt.Println(sum) // 15
}

实际应用示例

处理数据库查询

type User struct {
	ID   int
	Name string
}

func findUser(id int) mo.Option[User] {
	// 模拟数据库查询
	if id == 1 {
		return mo.Some(User{ID: 1, Name: "Alice"})
	}
	return mo.None[User]()
}

func getUserEmail(user User) mo.Option[string] {
	// 模拟获取邮箱
	if user.ID == 1 {
		return mo.Some("alice@example.com")
	}
	return mo.None[string]()
}

func main() {
	// 使用 Option 链式操作
	email := mo.FlatMap(findUser(1), getUserEmail)
	fmt.Println(email.OrElse("no email")) // alice@example.com

	email = mo.FlatMap(findUser(2), getUserEmail)
	fmt.Println(email.OrElse("no email")) // no email
}

错误处理管道

func parseInput(input string) mo.Either[error, int] {
	// 模拟解析
	if len(input) == 0 {
		return mo.Left[error, int](fmt.Errorf("empty input"))
	}
	return mo.Right[error, int](len(input))
}

func processValue(val int) mo.Either[error, string] {
	// 模拟处理
	if val > 10 {
		return mo.Left[error, string](fmt.Errorf("value too large"))
	}
	return mo.Right[error, string](fmt.Sprintf("processed-%d", val))
}

func main() {
	result := mo.FlatMapEither(parseInput("hello"), processValue)
	
	result.Match(
		func(err error) { fmt.Println("Error:", err) },
		func(val string) { fmt.Println("Result:", val) },
	) // 输出: Result: processed-5
}

mo 库通过这些抽象类型和函数式操作,使得 Golang 代码更加简洁、安全且易于维护。它特别适合需要处理大量可选值、错误或异步操作的场景。

回到顶部