Help us shape the future of Go! Take the 2026 Go Developer Survey

must

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 6, 2026 License: MIT Imports: 0 Imported by: 0

README

must

must 用于简化一段连续逻辑中的 Go 错误处理。OK、Get、Get2 和 Get3 会在收到非 nil error 时触发带有内部标记的 panic;Do、Call、Call2 和 Call3 在统一边界捕获这种 panic,并返回原始 error。

环境要求

  • Go 1.18 或更高版本

本库使用了 Go 1.18 引入的泛型,因此不支持更早的 Go 版本。

安装

go get github.com/viocha/must@v0.1.0
import "github.com/viocha/must"

为什么使用 must

假设一段逻辑需要依次解析端口、解析超时时间并校验配置,常规写法需要在每一步检查 error:

func loadSettings(rawPort, rawTimeout string) (int, time.Duration, error) {
	port, err := strconv.Atoi(rawPort)
	if err != nil {
		return 0, 0, err
	}

	timeout, err := time.ParseDuration(rawTimeout)
	if err != nil {
		return 0, 0, err
	}

	if err := validateSettings(port, timeout); err != nil {
		return 0, 0, err
	}

	return port, timeout, nil
}

使用 must 后,每个调用只保留业务返回值,错误在 Call2 边界统一返回:

func loadSettings(rawPort, rawTimeout string) (int, time.Duration, error) {
	return must.Call2(func() (int, time.Duration) {
		port := must.Get(strconv.Atoi(rawPort))
		timeout := must.Get(time.ParseDuration(rawTimeout))
		must.OK(validateSettings(port, timeout))
		return port, timeout
	})
}

闭包中连续调用了两次 Get 和一次 OK。任何一步失败都会立即终止后续逻辑,并由 Call2 返回对应的原始 error。

API

func OK(err error)
func Get[T any](v T, err error) T
func Get2[T1, T2 any](v1 T1, v2 T2, err error) (T1, T2)
func Get3[T1, T2, T3 any](v1 T1, v2 T2, v3 T3, err error) (T1, T2, T3)

func Do(fn func()) error
func Call[T any](fn func() T) (T, error)
func Call2[T1, T2 any](fn func() (T1, T2)) (T1, T2, error)
func Call3[T1, T2, T3 any](fn func() (T1, T2, T3)) (T1, T2, T3, error)

API 按业务返回值数量一一对应:

业务返回值数量 将 error 转为 panic 将 panic 转回 error
0 OK Do
1 Get Call
2 Get2 Call2
3 Get3 Call3

使用 Do

Do 用于没有业务返回值、只需要依次完成多个操作的场景:

err := must.Do(func() {
	must.OK(os.MkdirAll(directory, 0o755))
	must.OK(os.WriteFile(filename, data, 0o644))
})
if err != nil {
	return err
}

如果创建目录失败,不会继续写入文件;如果写入文件失败,Do 会返回 os.WriteFile 产生的原始 error。

使用 Call

Call 用于返回一个业务值:

config, err := must.Call(func() Config {
	data := must.Get(os.ReadFile(filename))
	var config Config
	must.OK(json.Unmarshal(data, &config))
	must.OK(config.Validate())
	return config
})

读取、解析或校验任意一步失败时,config 为 Config 的零值,err 为失败步骤产生的原始 error。

使用 Call2 和 Call3

Call2 用于返回两个业务值:

user, token, err := must.Call2(func() (User, string) {
	user := must.Get(loadUser(userID))
	token := must.Get(createToken(user))
	must.OK(saveLoginRecord(user, token))
	return user, token
})

Call3 用于返回三个业务值:

host, port, secure, err := must.Call3(func() (string, int, bool) {
	data := must.Get(os.ReadFile(filename))
	config := must.Get(parseServerConfig(data))
	must.OK(config.Validate())
	return config.Host, config.Port, config.Secure
})

发生错误时,Call2 或 Call3 会将所有业务返回值置为对应类型的零值,并返回原始 error。

panic 处理范围

Do、Call、Call2 和 Call3 只捕获由本包 OK、Get、Get2 或 Get3 触发的 panic。业务代码主动触发的 panic 和 Go runtime panic 不会被吞掉,而是保持原值继续向上传播。

err := must.Do(func() {
	value := must.Get(loadValue())
	must.OK(saveValue(value))
	panic("unexpected")
})

上面的 unexpected 不会被转换为 error,而会继续向上传播。

panic 只能在同一个 goroutine 中被 recover。不要期望外层的 Do 或 Call 捕获子 goroutine 中触发的 panic。

如果 OK 或 Get 系列触发的 panic 没有被 Do 或 Call 系列捕获,输出会同时包含 must 标记和原始错误消息:

panic: must: 原始错误消息

Documentation

Overview

must 包提供一组辅助函数,用于将返回值中的 error 转换为带标记的 panic, 并在指定边界通过 recover 将其还原为 error。

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Call

func Call[T any](fn func() T) (v T, err error)

Call 执行 fn。fn 正常返回时,Call 返回 fn 的返回值和 nil。 如果 fn 触发可识别的 panic,Call 返回 T 的零值和原始 error。

func Call2

func Call2[T1, T2 any](fn func() (T1, T2)) (v1 T1, v2 T2, err error)

Call2 执行 fn。fn 正常返回时,Call2 返回 fn 的两个返回值和 nil。 如果 fn 触发可识别的 panic,Call2 返回 T1、T2 的零值和原始 error。

func Call3

func Call3[T1, T2, T3 any](fn func() (T1, T2, T3)) (v1 T1, v2 T2, v3 T3, err error)

Call3 执行 fn。fn 正常返回时,Call3 返回 fn 的三个返回值和 nil。 如果 fn 触发可识别的 panic,Call3 返回 T1、T2、T3 的零值和原始 error。

func Do

func Do(fn func()) (err error)

Do 执行 fn。fn 正常返回时,Do 返回 nil。 如果 fn 的调用链中,OK、Get、Get2 或 Get3 因收到非 nil error 而触发 panic,Do 会通过 recover 捕获该 panic,并返回原始 error。

其他 panic 不会被 Do 捕获,而是保持原值继续向上传播。

func Get

func Get[T any](v T, err error) T

Get 在 err 为 nil 时返回 v,否则触发可由 Do、Call、Call2 或 Call3 识别的 panic。

func Get2

func Get2[T1, T2 any](v1 T1, v2 T2, err error) (T1, T2)

Get2 在 err 为 nil 时返回 v1 和 v2,否则触发可由 Do、Call、Call2 或 Call3 识别的 panic。

func Get3

func Get3[T1, T2, T3 any](v1 T1, v2 T2, v3 T3, err error) (T1, T2, T3)

Get3 在 err 为 nil 时返回 v1、v2 和 v3,否则触发可由 Do、Call、Call2 或 Call3 识别的 panic。

func OK

func OK(err error)

OK 在 err 为 nil 时直接返回,否则触发可由 Do、Call、Call2 或 Call3 识别的 panic。

Types

This section is empty.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL