A type-safe exception handling library based on Go generics that brings try-catch-like capabilities to Go.
- 🎯 Type-safe: Uses Go generics to ensure type-safe exception handling
- 🔗 Partial chaining: Supports chaining for
CatchAnyandFinally - 🏷️ Multiple error kinds: Built-in common error types (validation, database, network, business logic)
- 🔄 Finally support: Guarantees cleanup code execution
- 📦 Zero dependency: Pure Go implementation, no external dependencies
- 🚀 High performance: Built on Go's panic/recover with minimal overhead
tb.Catch[ErrorType](handler). Use the functional form instead: gotrycatch.Catch[ErrorType](tb, handler). CatchAny and Finally do support chaining.
go get github.com/linkerlin/gotrycatchpackage main
import (
"fmt"
"github.com/linkerlin/gotrycatch"
"github.com/linkerlin/gotrycatch/errors"
)
func main() {
tb := gotrycatch.Try(func() {
// Code that may panic
gotrycatch.Throw(errors.NewValidationError("email", "invalid format", 1001))
})
tb = gotrycatch.Catch[errors.ValidationError](tb, func(err errors.ValidationError) {
fmt.Printf("Validation error: %s (field: %s, code: %d)\n", err.Message, err.Field, err.Code)
})
tb.Finally(func() {
fmt.Println("Cleanup done")
})
}tb := gotrycatch.Try(func() {
// Business logic
processUserData()
})
tb = gotrycatch.Catch[errors.ValidationError](tb, func(err errors.ValidationError) {
fmt.Printf("Validation failed: %s\n", err.Message)
})
tb = gotrycatch.Catch[errors.DatabaseError](tb, func(err errors.DatabaseError) {
fmt.Printf("Database error: %s\n", err.Operation)
})
tb = gotrycatch.Catch[errors.NetworkError](tb, func(err errors.NetworkError) {
if err.Timeout {
fmt.Printf("Network timeout: %s\n", err.URL)
} else {
fmt.Printf("Network error %d: %s\n", err.StatusCode, err.URL)
}
})
tb = tb.CatchAny(func(err interface{}) {
fmt.Printf("Unknown error: %v\n", err)
})
tb.Finally(func() {
fmt.Println("Processing done")
})tb := gotrycatch.Try(func() {
validateUserInput(userData)
})
result, tb := gotrycatch.CatchWithReturn[errors.ValidationError](tb, func(err errors.ValidationError) interface{} {
return map[string]interface{}{
"success": false,
"error": err.Error(),
"code": err.Code,
}
})
if result != nil {
fmt.Printf("Result: %+v\n", result)
}The library provides the following common error types:
err := errors.NewValidationError("email", "invalid email format", 1001)err := errors.NewDatabaseError("SELECT", "users", sqlErr)// HTTP error
err := errors.NewNetworkError("http://api.example.com", 404)
// Timeout error
err := errors.NewNetworkTimeoutError("http://api.example.com")err := errors.NewBusinessLogicError("age_limit", "user must be at least 18 years old")Executes the given function and captures any panic. Returns a TryBlock for subsequent handling.
Handles exceptions of type T. If the panic value can be converted to T, the handler is invoked.
Like Catch, but allows the handler to return a value.
Handles any unhandled exception regardless of its type.
Executes cleanup code whether or not an exception occurred. If an exception remains unhandled, it is rethrown after the finally block.
Throws an exception (creates a panic).
- Order
Catchblocks by specificity: most specific first, more general later - Always use
Finallyto ensure resource cleanup - Prefer predefined error types over raw strings or numbers
- Avoid throwing in
Finallyto not mask the original exception
- Built on Go's panic/recover; cost occurs only when exceptions actually happen
- Near-zero overhead on the normal execution path
- Try-Catch blocks can be nested without significant impact
- Requires Go 1.18+ (generics)
- Fully compatible with the standard library
- Can coexist with existing error-handling code
A: Because methods cannot have generic type parameters in Go. So this is not supported:
// ❌ Not supported
tb := gotrycatch.Try(func() { ... }).Catch[ErrorType](handler)Use the functional form instead:
// ✅ Correct
tb := gotrycatch.Try(func() { ... })
tb = gotrycatch.Catch[ErrorType](tb, handler)But CatchAny and Finally support chaining:
// ✅ Supported
tb.CatchAny(handler).Finally(cleanup)A: Exception handling relies on Go's panic/recover. Overhead is incurred only when an exception actually occurs. The normal path overhead is near zero.
See the examples/ directory for more:
- Basic usage
- Handling multiple error types
- Nested exception handling
- Real-world scenarios
# Quick demo
go run ./cmd/demo
# Full examples
go run ./examples
# Run tests
go test -vMIT License
A lib for using trycatch in Go!
一个基于 Go 泛型的类型安全异常处理库,提供类似于其他语言中 try-catch 语句的功能。
- 🎯 类型安全: 使用 Go 泛型确保异常处理的类型安全
- 🔗 部分链式调用: 支持
CatchAny和Finally的链式调用 - 🏷️ 多种异常类型: 内置常用的异常类型(验证、数据库、网络、业务逻辑错误)
- 🔄 Finally 支持: 保证清理代码的执行
- 📦 零依赖: 纯 Go 实现,无外部依赖
- 🚀 高性能: 基于 Go 的 panic/recover 机制,性能开销极小
tb.Catch[ErrorType](handler)。需要使用函数式调用:gotrycatch.Catch[ErrorType](tb, handler)。但是 CatchAny 和 Finally 方法支持链式调用。
go get github.com/linkerlin/gotrycatchpackage main
import (
"fmt"
"github.com/linkerlin/gotrycatch"
"github.com/linkerlin/gotrycatch/errors"
)
func main() {
tb := gotrycatch.Try(func() {
// 可能会 panic 的代码
gotrycatch.Throw(errors.NewValidationError("email", "invalid format", 1001))
})
tb = gotrycatch.Catch[errors.ValidationError](tb, func(err errors.ValidationError) {
fmt.Printf("验证错误: %s (字段: %s, 代码: %d)\n", err.Message, err.Field, err.Code)
})
tb.Finally(func() {
fmt.Println("清理工作完成")
})
}tb := gotrycatch.Try(func() {
// 业务逻辑代码
processUserData()
})
tb = gotrycatch.Catch[errors.ValidationError](tb, func(err errors.ValidationError) {
fmt.Printf("验证失败: %s\n", err.Message)
})
tb = gotrycatch.Catch[errors.DatabaseError](tb, func(err errors.DatabaseError) {
fmt.Printf("数据库错误: %s\n", err.Operation)
})
tb = gotrycatch.Catch[errors.NetworkError](tb, func(err errors.NetworkError) {
if err.Timeout {
fmt.Printf("网络超时: %s\n", err.URL)
} else {
fmt.Printf("网络错误 %d: %s\n", err.StatusCode, err.URL)
}
})
tb = tb.CatchAny(func(err interface{}) {
fmt.Printf("未知错误: %v\n", err)
})
tb.Finally(func() {
fmt.Println("处理完成")
})tb := gotrycatch.Try(func() {
validateUserInput(userData)
})
result, tb := gotrycatch.CatchWithReturn[errors.ValidationError](tb, func(err errors.ValidationError) interface{} {
return map[string]interface{}{
"success": false,
"error": err.Error(),
"code": err.Code,
}
})
if result != nil {
fmt.Printf("处理结果: %+v\n", result)
}库提供了以下常用的异常类型:
err := errors.NewValidationError("email", "邮箱格式无效", 1001)err := errors.NewDatabaseError("SELECT", "users", sqlErr)// HTTP 错误
err := errors.NewNetworkError("http://api.example.com", 404)
// 超时错误
err := errors.NewNetworkTimeoutError("http://api.example.com")err := errors.NewBusinessLogicError("age_limit", "用户必须年满18岁")执行给定的函数并捕获任何 panic。返回一个 TryBlock 用于后续的异常处理。
处理指定类型 T 的异常。如果 panic 的值可以转换为类型 T,则调用处理函数。
类似于 Catch,但允许处理函数返回一个值。
处理任何未被处理的异常,无论类型如何。
无论是否发生异常,都会执行的清理代码。如果有未处理的异常,会在 finally 块执行后重新抛出。
抛出一个异常(创建 panic)。
- 按特定性排序 Catch 块: 将最具体的异常类型放在前面,通用类型放在后面
- 总是使用 Finally: 确保资源清理代码被执行
- 使用预定义异常类型: 优先使用库提供的异常类型,而不是原始字符串或数字
- 避免在 Finally 中抛出异常: 这可能会掩盖原始异常
- 异常处理基于 Go 的 panic/recover 机制,只在实际发生异常时才有性能开销
- 正常执行路径的性能开销接近零
- Try-Catch 块可以嵌套使用,不会显著影响性能
- 需要 Go 1.18+ (泛型支持)
- 与标准库完全兼容
- 可以与现有的错误处理代码共存
A: 由于 Go 语言的限制,方法不能有泛型类型参数。因此不能写:
// ❌ 这样写是不支持的
tb := gotrycatch.Try(func() { ... }).Catch[ErrorType](handler)只能使用函数式调用:
// ✅ 正确的写法
tb := gotrycatch.Try(func() { ... })
tb = gotrycatch.Catch[ErrorType](tb, handler)但是 CatchAny 和 Finally 方法支持链式调用:
// ✅ 这样是可以的
tb.CatchAny(handler).Finally(cleanup)A: 异常处理基于 Go 的 panic/recover 机制,只在实际发生异常时才有性能开销。正常执行路径的性能开销接近零。
查看 examples/ 目录获取更多详细示例,包括:
- 基本用法演示
- 多种异常类型处理
- 嵌套异常处理
- 真实场景应用示例
# 快速演示
go run ./cmd/demo
# 完整示例
go run ./examples
# 运行测试
go test -vMIT License A lib for using trycatch in Go!