must

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Nov 12, 2019 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package must implements helper functions to simplify repetitive error handling.

Mainly there are 3 ways to handle errors.

- Return errors. - Panic. - Handle errors.

This package provides a way to hide error handling and focus on the main logic. The code may look a lot cleaner. The downside is that the explicit return statement is hidden to look unclear.

Well written Go code indents error flow and the function should be short enough, so this package shouldn't be required. (But Go 2 draft seems to adopt this idea.)

By default, must panics. If you'd like to return error by default (like Go 2 try proposal), defer ReturnErr(&err) in the beginning. If you'd like to wrap the error, you may use HandleErrorf(&err, "format string", args...), and this works with both normal error return and try-like must.

You may customize error handling more flexible way using HandleErr.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Any

func Any(v0 interface{}, err error) interface{}

Any panics if err is non-nil and returns interface{}.

Example
// TODO: Fix the fragile test dependency to the error message.
err := func() (err error) {
	defer ReturnErr(&err)

	// Any can be used with any types, but it's less efficient. For
	// any types that must package does not support, consider
	// writing your own 2-line defer function, or use Any.
	var i = Any(strconv.Atoi("a")).(int)
	fmt.Println(i)

	return nil
}()
fmt.Println(err)
Output:

strconv.Atoi: parsing "a": invalid syntax

func Bool

func Bool(v0 bool, err error) bool

Bool panics if err is non-nil and returns bool.

func Bools

func Bools(v0 []bool, err error) []bool

Bools panics if err is non-nil and returns []bool.

func Byte

func Byte(v0 byte, err error) byte

Byte panics if err is non-nil and returns byte.

func Bytes

func Bytes(v0 []byte, err error) []byte

Bytes panics if err is non-nil and returns []byte.

func BytesBool

func BytesBool(v0 []byte, v1 bool, err error) ([]byte, bool)

BytesBool panics if err is non-nil and returns ([]byte, bool).

func CheckErr

func CheckErr(err error, skip int)

CheckErr panics if err is non-nil and put the filename and line number and skip is the number of stack fragments to ascend. This function could be used to write custom must functions.

func Complex128

func Complex128(v0 complex128, err error) complex128

Complex128 panics if err is non-nil and returns complex128.

func Complex128s

func Complex128s(v0 []complex128, err error) []complex128

Complex128s panics if err is non-nil and returns []complex128.

func Complex64

func Complex64(v0 complex64, err error) complex64

Complex64 panics if err is non-nil and returns complex64.

func Complex64s

func Complex64s(v0 []complex64, err error) []complex64

Complex64s panics if err is non-nil and returns []complex64.

func Float32

func Float32(v0 float32, err error) float32

Float32 panics if err is non-nil and returns float32.

func Float32s

func Float32s(v0 []float32, err error) []float32

Float32s panics if err is non-nil and returns []float32.

func Float64

func Float64(v0 float64, err error) float64

Float64 panics if err is non-nil and returns float64.

func Float64s

func Float64s(v0 []float64, err error) []float64

Float64s panics if err is non-nil and returns []float64.

func HandleErr

func HandleErr(handler func(error))

HandleErr is a defer function to customize error handling. This can be used in case the returning error is custom typed or logging is required.

Example (FromGoVersion2Draft)
// Translation of the code example of Go 2 error handling draft.
// https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md
copyFile := func(src, dst string) (err error) {
	// Param name is newerr for err visibility.
	defer HandleErr(func(newerr error) {
		err = fmt.Errorf("copy %s %s: %v", src, dst, newerr)
	})

	r := Any(os.Open(src)).(*os.File)
	defer r.Close()

	w := Any(os.Create(dst)).(*os.File)
	// Note that this should be HandleErrNext(), not HandleErr().
	defer HandleErrNext(func(error) {
		w.Close()
		os.Remove(dst) // (only if a check fails)
	})

	Int64(io.Copy(w, r))
	Nil(w.Close())
	return nil
}
_ = copyFile
Output:

Example (FromGoVersion2DraftTestedSuccess)
// To demonstrate how it works when successful.
copyFile := func(src, dst string) (err error) {
	// Param name is newerr for err visibility.
	defer HandleErr(func(newerr error) {
		err = fmt.Errorf("copy %s %s: %v", src, dst, newerr)
	})

	r := fmt.Sprintf("*File(%q)", src)
	fmt.Printf("os.Open(src) is called: %q\n", src)
	defer func() {
		fmt.Printf("r.Close() is called: %s\n", r)
	}()

	w := fmt.Sprintf("*File(%q)", dst)
	fmt.Printf("os.Create(dst) is called: %q\n", dst)
	// Note that this should be HandleErrNext(), not HandleErr().
	defer HandleErrNext(func(newerr error) {
		fmt.Printf("w.Close() is called in defer: %s\n", w)
		fmt.Printf("os.Remove(dst) is called: %q\n", dst)
	})

	fmt.Println("io.Copy(w, r) is called")
	fmt.Printf("w.Close() is called: %s\n", w)
	return nil
}
fmt.Println("returned error:", copyFile("input.txt", "output.txt"))
Output:

os.Open(src) is called: "input.txt"
os.Create(dst) is called: "output.txt"
io.Copy(w, r) is called
w.Close() is called: *File("output.txt")
r.Close() is called: *File("input.txt")
returned error: <nil>
Example (FromGoVersion2DraftTestedWriteFail)
// To demonstrate how it works when successful.
copyFile := func(src, dst string) (err error) {
	// Param name is newerr for err visibility.
	defer HandleErr(func(newerr error) {
		err = fmt.Errorf("copy %s %s: %v", src, dst, newerr)
	})

	r := fmt.Sprintf("*File(%q)", src)
	fmt.Printf("os.Open(src) is called: %q\n", src)
	defer func() {
		fmt.Printf("r.Close() is called: %s\n", r)
	}()

	w := fmt.Sprintf("*File(%q)", dst)
	fmt.Printf("os.Create(dst) is called: %q\n", dst)
	// Note that this should be HandleErrNext(), not HandleErr().
	defer HandleErrNext(func(newerr error) {
		fmt.Printf("w.Close() is called in defer: %s\n", w)
		fmt.Printf("os.Remove(dst) is called: %q\n", dst)
	})

	fmt.Println("io.Copy(w, r) is called")
	Nil(errors.New("cannot write file"))
	fmt.Printf("w.Close() is called: %s\n", w)
	return nil
}
fmt.Println("returned error:", copyFile("input.txt", "output.txt"))
Output:

os.Open(src) is called: "input.txt"
os.Create(dst) is called: "output.txt"
io.Copy(w, r) is called
w.Close() is called in defer: *File("output.txt")
os.Remove(dst) is called: "output.txt"
r.Close() is called: *File("input.txt")
returned error: copy input.txt output.txt: cannot write file
Example (JustReturnError)
// TODO: Fix the fragile test dependency to the error message.
err := func() (err error) {
	// Equivalent with ReturnErr(&err). Param name is newerr for err
	// visibility.
	defer HandleErr(func(newerr error) {
		err = newerr
	})
	fmt.Println(Int(strconv.Atoi("a")))
	return nil
}()
fmt.Println(err)
Output:

strconv.Atoi: parsing "a": invalid syntax
Example (WrapError)
// TODO: Fix the fragile test dependency to the error message.
//
// This example shows how to wrap the error. You may use more
// sophisticated wrappers like "github.com/pkg/errors".Wrap or multi
// error appender.
err := func() (err error) {
	defer HandleErr(func(newerr error) {
		err = fmt.Errorf("error occurred: %v", newerr)
	})
	fmt.Println(Int(strconv.Atoi("a")))
	return nil
}()
fmt.Println(err)
Output:

error occurred: strconv.Atoi: parsing "a": invalid syntax

func HandleErrNext

func HandleErrNext(handler func(error))

HandleErrNext is a defer function to customize the following (2nd, 3rd, ...) error handling. This is similar to HandleErr except the panic is not consumed. Use this to let other deferred handlers above handle the error as well.

func HandleErrorf

func HandleErrorf(perr *error, format string, args ...interface{})

HandleErrorf is a defer function to wrap the error. It appears in Go 2 try proposal. Implicitly it does what ReturnErr(&err), because try always returns. If you'd like to use try without HandleErrorf, use ReturnErr, since the deafult behavior of must check is panic. In case you defer HandleErrorf, you don't need to defer ReturnErr.

Here's the link to Go 2 try proposal: https://github.com/golang/go/issues/32437

Example (Multiple)
f := func(id int) (err error) {
	defer HandleErrorf(&err, "error occurred in example %d", id)
	fmt.Println("running well")
	defer HandleErrorf(&err, "after running well")
	fmt.Println(Int(strconv.Atoi("a")))
	return nil
}
fmt.Println(f(10))
Output:

running well
error occurred in example 10: after running well: strconv.Atoi: parsing "a": invalid syntax
Example (Must)
f := func(id int) (err error) {
	defer HandleErrorf(&err, "error occurred in example %d", id)
	fmt.Println(Int(strconv.Atoi("a")))
	return nil
}
fmt.Println(f(10))
Output:

error occurred in example 10: strconv.Atoi: parsing "a": invalid syntax
Example (ReturnError)
f := func(id int) (err error) {
	defer HandleErrorf(&err, "error occurred in example %d", id)
	return errors.New("failed")
}
fmt.Println(f(10))
Output:

error occurred in example 10: failed

func Int

func Int(v0 int, err error) int

Int panics if err is non-nil and returns int.

func Int16

func Int16(v0 int16, err error) int16

Int16 panics if err is non-nil and returns int16.

func Int16s

func Int16s(v0 []int16, err error) []int16

Int16s panics if err is non-nil and returns []int16.

func Int32

func Int32(v0 int32, err error) int32

Int32 panics if err is non-nil and returns int32.

func Int32s

func Int32s(v0 []int32, err error) []int32

Int32s panics if err is non-nil and returns []int32.

func Int64

func Int64(v0 int64, err error) int64

Int64 panics if err is non-nil and returns int64.

func Int64s

func Int64s(v0 []int64, err error) []int64

Int64s panics if err is non-nil and returns []int64.

func Int8

func Int8(v0 int8, err error) int8

Int8 panics if err is non-nil and returns int8.

func Int8s

func Int8s(v0 []int8, err error) []int8

Int8s panics if err is non-nil and returns []int8.

func IntBytes

func IntBytes(v0 int, v1 []byte, err error) (int, []byte)

IntBytes panics if err is non-nil and returns (int, []byte).

func Ints

func Ints(v0 []int, err error) []int

Ints panics if err is non-nil and returns []int.

func LogErr

func LogErr(logger func(...interface{}))

LogErr is a defer function to simplify logging.

Example
// TODO: Fix the fragile test dependency to the error message.
//
// This is probably an anti-pattern because error was logged and
// returned, handled twice.
err := func() (err error) {
	defer ReturnErr(&err)
	// Log error to stderr with file name and line number.
	defer LogErr(log.Println)
	i := Int(strconv.Atoi("a"))
	fmt.Printf("i = %d\n", i)
	return nil
}()
fmt.Println(err)
Output:

strconv.Atoi: parsing "a": invalid syntax

func Nil

func Nil(err error)

Nil panics if err is non-nil.

func ReturnErr

func ReturnErr(perr *error)

ReturnErr is a defer function to simplify returning errors. The pointer to the returning error variable perr should be passed. Errors captured by must package are handled. Other panic values won't be handled here.

Example
// TODO: Fix the fragile test dependency to the error message.
err := func() (err error) {
	// All errors captured by must package is returned. Without this
	// defer line captured errors will panic.
	defer ReturnErr(&err)

	// Error handling is simplified here.
	// From other packages it looks like must.Int(...).
	i := Int(strconv.Atoi("a"))
	fmt.Println(i)

	// Or inlined.
	fmt.Println(Int(strconv.Atoi("b")))

	// Compare with the following.
	i, err = strconv.Atoi("c")
	if err != nil {
		return err
	}
	fmt.Println(i)

	return nil
}()
fmt.Println(err)
Output:

strconv.Atoi: parsing "a": invalid syntax
Example (MultipleRecover)
_ = func() (err error) {
	// Deferred calls are executed in last-in-first-out order. If a
	// deferred function recovers from any panic, defer of the
	// function should come before defer ReturnErr.
	defer recoverAnyPanic()
	defer ReturnErr(&err)

	_ = Int(strconv.Atoi("1"))
	panic(errors.New("created panic"))
}()
Output:

panic: created panic

func Rune

func Rune(v0 rune, err error) rune

Rune panics if err is non-nil and returns rune.

func RuneBoolString

func RuneBoolString(v0 rune, v1 bool, v2 string, err error) (rune, bool, string)

RuneBoolString panics if err is non-nil and returns (rune, bool, string).

func RuneInt

func RuneInt(v0 rune, v1 int, err error) (rune, int)

RuneInt panics if err is non-nil and returns (rune, int).

func Runes

func Runes(v0 []rune, err error) []rune

Runes panics if err is non-nil and returns []rune.

func String

func String(v0 string, err error) string

String panics if err is non-nil and returns string.

func Strings

func Strings(v0 []string, err error) []string

Strings panics if err is non-nil and returns []string.

func Uint

func Uint(v0 uint, err error) uint

Uint panics if err is non-nil and returns uint.

func Uint16

func Uint16(v0 uint16, err error) uint16

Uint16 panics if err is non-nil and returns uint16.

func Uint16s

func Uint16s(v0 []uint16, err error) []uint16

Uint16s panics if err is non-nil and returns []uint16.

func Uint32

func Uint32(v0 uint32, err error) uint32

Uint32 panics if err is non-nil and returns uint32.

func Uint32s

func Uint32s(v0 []uint32, err error) []uint32

Uint32s panics if err is non-nil and returns []uint32.

func Uint64

func Uint64(v0 uint64, err error) uint64

Uint64 panics if err is non-nil and returns uint64.

func Uint64s

func Uint64s(v0 []uint64, err error) []uint64

Uint64s panics if err is non-nil and returns []uint64.

func Uint8

func Uint8(v0 uint8, err error) uint8

Uint8 panics if err is non-nil and returns uint8.

func Uint8s

func Uint8s(v0 []uint8, err error) []uint8

Uint8s panics if err is non-nil and returns []uint8.

func Uintptr

func Uintptr(v0 uintptr, err error) uintptr

Uintptr panics if err is non-nil and returns uintptr.

func Uintptrs

func Uintptrs(v0 []uintptr, err error) []uintptr

Uintptrs panics if err is non-nil and returns []uintptr.

func Uints

func Uints(v0 []uint, err error) []uint

Uints panics if err is non-nil and returns []uint.

Types

This section is empty.

Jump to

Keyboard shortcuts

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