Files
golang/golang-learning/07-error-handling/02-custom-errors.go
2025-08-24 11:24:52 +08:00

1072 lines
26 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
02-custom-errors.go - Go 语言自定义错误详解
学习目标:
1. 理解自定义错误的必要性
2. 掌握自定义错误类型的设计
3. 学会实现 error 接口
4. 了解错误的分类和层次
5. 掌握错误的序列化和反序列化
知识点:
- 自定义错误类型的设计
- 实现 error 接口
- 错误的分类和层次结构
- 错误的附加信息
- 错误的序列化
- 错误的本地化
*/
package main
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
)
func main() {
fmt.Println("=== Go 语言自定义错误详解 ===\\n")
// 演示基本自定义错误
demonstrateBasicCustomErrors()
// 演示结构化错误
demonstrateStructuredErrors()
// 演示错误分类
demonstrateErrorClassification()
// 演示错误层次结构
demonstrateErrorHierarchy()
// 演示错误的附加信息
demonstrateErrorWithDetails()
// 演示错误的序列化
demonstrateErrorSerialization()
// 演示实际应用场景
demonstratePracticalCustomErrors()
}
// demonstrateBasicCustomErrors 演示基本自定义错误
func demonstrateBasicCustomErrors() {
fmt.Println("1. 基本自定义错误:")
// 简单自定义错误
fmt.Printf(" 简单自定义错误:\\n")
err := &SimpleError{Message: "这是一个简单的自定义错误"}
fmt.Printf(" 错误: %v\\n", err)
fmt.Printf(" 错误类型: %T\\n", err)
// 带代码的错误
fmt.Printf(" 带代码的错误:\\n")
codeErr := &CodeError{
Code: 1001,
Message: "用户输入无效",
}
fmt.Printf(" 错误: %v\\n", codeErr)
fmt.Printf(" 错误代码: %d\\n", codeErr.Code)
// 带时间戳的错误
fmt.Printf(" 带时间戳的错误:\\n")
timeErr := &TimestampError{
Message: "操作失败",
Timestamp: time.Now(),
}
fmt.Printf(" 错误: %v\\n", timeErr)
// 带上下文的错误
fmt.Printf(" 带上下文的错误:\\n")
contextErr := &ContextError{
Operation: "数据库查询",
Resource: "用户表",
Message: "连接超时",
}
fmt.Printf(" 错误: %v\\n", contextErr)
fmt.Println()
}
// demonstrateStructuredErrors 演示结构化错误
func demonstrateStructuredErrors() {
fmt.Println("2. 结构化错误:")
// 验证错误
fmt.Printf(" 验证错误:\\n")
validationErr := &ValidationError{
Field: "email",
Value: "invalid-email",
Rule: "email_format",
Message: "邮箱格式不正确",
}
fmt.Printf(" 验证错误: %v\\n", validationErr)
// HTTP 错误
fmt.Printf(" HTTP 错误:\\n")
httpErr := &HTTPError{
StatusCode: http.StatusNotFound,
Method: "GET",
URL: "/api/users/999",
Message: "用户不存在",
}
fmt.Printf(" HTTP错误: %v\\n", httpErr)
fmt.Printf(" 状态码: %d\\n", httpErr.StatusCode)
fmt.Printf(" 是否客户端错误: %t\\n", httpErr.IsClientError())
fmt.Printf(" 是否服务器错误: %t\\n", httpErr.IsServerError())
// 数据库错误
fmt.Printf(" 数据库错误:\\n")
dbErr := &DatabaseError{
Operation: "INSERT",
Table: "users",
Query: "INSERT INTO users (name, email) VALUES (?, ?)",
SQLState: "23000",
Message: "重复键值违反唯一约束",
}
fmt.Printf(" 数据库错误: %v\\n", dbErr)
fmt.Printf(" 是否约束违反: %t\\n", dbErr.IsConstraintViolation())
// 业务逻辑错误
fmt.Printf(" 业务逻辑错误:\\n")
businessErr := &BusinessError{
Domain: "用户管理",
Rule: "年龄限制",
Message: "用户年龄必须在18-65岁之间",
Severity: "ERROR",
Retryable: false,
}
fmt.Printf(" 业务错误: %v\\n", businessErr)
fmt.Printf(" 可重试: %t\\n", businessErr.Retryable)
fmt.Println()
}
// demonstrateErrorClassification 演示错误分类
func demonstrateErrorClassification() {
fmt.Println("3. 错误分类:")
// 临时错误 vs 永久错误
fmt.Printf(" 临时错误 vs 永久错误:\\n")
tempErr := &TemporaryError{
Message: "网络连接超时",
Temporary: true,
RetryAfter: 5 * time.Second,
}
fmt.Printf(" 临时错误: %v\\n", tempErr)
fmt.Printf(" 是否临时: %t\\n", tempErr.IsTemporary())
fmt.Printf(" 重试间隔: %v\\n", tempErr.RetryAfter)
permErr := &PermanentError{
Message: "认证失败无效的API密钥",
Reason: "INVALID_CREDENTIALS",
}
fmt.Printf(" 永久错误: %v\\n", permErr)
fmt.Printf(" 是否临时: %t\\n", permErr.IsTemporary())
// 可恢复错误 vs 不可恢复错误
fmt.Printf(" 可恢复错误 vs 不可恢复错误:\\n")
recoverableErr := &RecoverableError{
Message: "磁盘空间不足",
RecoveryHint: "请清理磁盘空间后重试",
}
fmt.Printf(" 可恢复错误: %v\\n", recoverableErr)
fmt.Printf(" 恢复提示: %s\\n", recoverableErr.RecoveryHint)
fatalErr := &FatalError{
Message: "系统内存不足,程序无法继续运行",
Cause: "OUT_OF_MEMORY",
}
fmt.Printf(" 致命错误: %v\\n", fatalErr)
// 用户错误 vs 系统错误
fmt.Printf(" 用户错误 vs 系统错误:\\n")
userErr := &UserError{
Message: "密码长度至少8位",
UserMessage: "请输入至少8位字符的密码",
Field: "password",
}
fmt.Printf(" 用户错误: %v\\n", userErr)
fmt.Printf(" 用户友好消息: %s\\n", userErr.UserMessage)
systemErr := &SystemError{
Message: "数据库连接池耗尽",
Component: "database",
Level: "CRITICAL",
}
fmt.Printf(" 系统错误: %v\\n", systemErr)
fmt.Printf(" 组件: %s\\n", systemErr.Component)
fmt.Println()
}
// demonstrateErrorHierarchy 演示错误层次结构
func demonstrateErrorHierarchy() {
fmt.Println("4. 错误层次结构:")
// 基础错误接口
fmt.Printf(" 基础错误接口:\\n")
var err error
// 网络错误层次
err = &NetworkError{
BaseError: BaseError{
Code: "NET001",
Message: "网络连接失败",
Timestamp: time.Now(),
},
Host: "api.example.com",
Port: 443,
Timeout: 30 * time.Second,
}
fmt.Printf(" 网络错误: %v\\n", err)
// 检查错误类型
if netErr, ok := err.(*NetworkError); ok {
fmt.Printf(" 主机: %s\\n", netErr.Host)
fmt.Printf(" 端口: %d\\n", netErr.Port)
fmt.Printf(" 超时: %v\\n", netErr.Timeout)
}
// 应用错误层次
err = &ApplicationError{
BaseError: BaseError{
Code: "APP001",
Message: "应用程序错误",
Timestamp: time.Now(),
},
Module: "用户服务",
Version: "1.2.3",
Stack: []string{"main.go:42", "user.go:15", "db.go:89"},
}
fmt.Printf(" 应用错误: %v\\n", err)
if appErr, ok := err.(*ApplicationError); ok {
fmt.Printf(" 模块: %s\\n", appErr.Module)
fmt.Printf(" 版本: %s\\n", appErr.Version)
fmt.Printf(" 调用栈: %v\\n", appErr.Stack)
}
// 错误链
fmt.Printf(" 错误链:\\n")
rootErr := &BaseError{
Code: "DB001",
Message: "数据库连接失败",
}
serviceErr := &ServiceError{
BaseError: BaseError{
Code: "SVC001",
Message: "服务调用失败",
},
Service: "用户服务",
Cause: rootErr,
}
apiErr := &APIError{
BaseError: BaseError{
Code: "API001",
Message: "API请求失败",
},
Endpoint: "/api/users",
Cause: serviceErr,
}
fmt.Printf(" API错误链: %v\\n", apiErr)
printErrorChain(apiErr, " ")
fmt.Println()
}
// demonstrateErrorWithDetails 演示错误的附加信息
func demonstrateErrorWithDetails() {
fmt.Println("5. 错误的附加信息:")
// 带详细信息的错误
fmt.Printf(" 带详细信息的错误:\\n")
detailedErr := &DetailedError{
Code: "VALIDATION_FAILED",
Message: "数据验证失败",
Details: map[string]interface{}{
"field": "age",
"value": -5,
"constraint": "must be positive",
"suggested_fix": "请输入正数",
"documentation": "https://docs.example.com/validation",
},
}
fmt.Printf(" 详细错误: %v\\n", detailedErr)
fmt.Printf(" 详细信息:\\n")
for key, value := range detailedErr.Details {
fmt.Printf(" %s: %v\\n", key, value)
}
// 带元数据的错误
fmt.Printf(" 带元数据的错误:\\n")
metaErr := &MetadataError{
Message: "文件处理失败",
Metadata: ErrorMetadata{
RequestID: "req-12345",
UserID: "user-67890",
SessionID: "sess-abcdef",
TraceID: "trace-xyz789",
Environment: "production",
Version: "v1.0.0",
},
}
fmt.Printf(" 元数据错误: %v\\n", metaErr)
fmt.Printf(" 请求ID: %s\\n", metaErr.Metadata.RequestID)
fmt.Printf(" 用户ID: %s\\n", metaErr.Metadata.UserID)
fmt.Printf(" 环境: %s\\n", metaErr.Metadata.Environment)
// 带建议的错误
fmt.Printf(" 带建议的错误:\\n")
suggestErr := &SuggestedError{
Message: "配置文件格式错误",
Suggestions: []string{
"检查JSON语法是否正确",
"确保所有字符串都用双引号包围",
"验证配置文件的结构",
"参考示例配置文件",
},
HelpURL: "https://docs.example.com/config",
}
fmt.Printf(" 建议错误: %v\\n", suggestErr)
fmt.Printf(" 建议:\\n")
for i, suggestion := range suggestErr.Suggestions {
fmt.Printf(" %d. %s\\n", i+1, suggestion)
}
fmt.Printf(" 帮助链接: %s\\n", suggestErr.HelpURL)
fmt.Println()
}
// demonstrateErrorSerialization 演示错误的序列化
func demonstrateErrorSerialization() {
fmt.Println("6. 错误的序列化:")
// JSON 序列化
fmt.Printf(" JSON 序列化:\\n")
serializableErr := &SerializableError{
Code: "ERR001",
Message: "操作失败",
Timestamp: time.Now(),
Details: map[string]interface{}{
"operation": "user_create",
"reason": "duplicate_email",
"email": "user@example.com",
},
}
// 序列化为JSON
jsonData, err := json.MarshalIndent(serializableErr, "", " ")
if err != nil {
fmt.Printf(" 序列化失败: %v\\n", err)
} else {
fmt.Printf(" JSON序列化结果:\\n%s\\n", string(jsonData))
}
// 从JSON反序列化
var deserializedErr SerializableError
err = json.Unmarshal(jsonData, &deserializedErr)
if err != nil {
fmt.Printf(" 反序列化失败: %v\\n", err)
} else {
fmt.Printf(" 反序列化结果: %v\\n", &deserializedErr)
}
// 错误传输
fmt.Printf(" 错误传输:\\n")
transportErr := &TransportError{
ID: "err-12345",
Type: "ValidationError",
Message: "输入验证失败",
Code: 400,
Timestamp: time.Now().Unix(),
Data: map[string]interface{}{
"field": "email",
"value": "invalid",
},
}
// 模拟网络传输
transmitted := transmitError(transportErr)
fmt.Printf(" 传输的错误: %v\\n", transmitted)
// 错误本地化
fmt.Printf(" 错误本地化:\\n")
localizedErr := &LocalizedError{
Code: "USER_NOT_FOUND",
Message: "User not found",
Locale: "en",
Translations: map[string]string{
"en": "User not found",
"zh": "用户未找到",
"ja": "ユーザーが見つかりません",
"fr": "Utilisateur non trouvé",
},
}
fmt.Printf(" 英文: %s\\n", localizedErr.GetMessage("en"))
fmt.Printf(" 中文: %s\\n", localizedErr.GetMessage("zh"))
fmt.Printf(" 日文: %s\\n", localizedErr.GetMessage("ja"))
fmt.Printf(" 法文: %s\\n", localizedErr.GetMessage("fr"))
fmt.Printf(" 默认: %s\\n", localizedErr.GetMessage("unknown"))
fmt.Println()
}
// demonstratePracticalCustomErrors 演示实际应用场景
func demonstratePracticalCustomErrors() {
fmt.Println("7. 实际应用场景:")
// Web API 错误处理
fmt.Printf(" Web API 错误处理:\\n")
apiErrors := []error{
&APIError{
BaseError: BaseError{Code: "AUTH001", Message: "认证失败"},
Endpoint: "/api/login",
},
&APIError{
BaseError: BaseError{Code: "RATE001", Message: "请求频率超限"},
Endpoint: "/api/data",
},
&APIError{
BaseError: BaseError{Code: "VAL001", Message: "参数验证失败"},
Endpoint: "/api/users",
},
}
for _, err := range apiErrors {
handleAPIError(err)
}
// 数据库操作错误
fmt.Printf(" 数据库操作错误:\\n")
dbErrors := []error{
&DatabaseError{
Operation: "SELECT",
Table: "users",
SQLState: "42000",
Message: "语法错误",
},
&DatabaseError{
Operation: "INSERT",
Table: "orders",
SQLState: "23505",
Message: "唯一约束违反",
},
&DatabaseError{
Operation: "UPDATE",
Table: "products",
SQLState: "40001",
Message: "死锁检测",
},
}
for _, err := range dbErrors {
handleDatabaseError(err)
}
// 文件操作错误
fmt.Printf(" 文件操作错误:\\n")
fileErr := &FileError{
Operation: "read",
Path: "/etc/config.json",
Message: "权限被拒绝",
OSError: "permission denied",
}
handleFileError(fileErr)
// 业务规则错误
fmt.Printf(" 业务规则错误:\\n")
businessErrors := []*BusinessRuleError{
{
Rule: "最小订单金额",
Description: "订单金额必须大于100元",
Value: "50",
Constraint: "> 100",
},
{
Rule: "库存检查",
Description: "商品库存不足",
Value: "2",
Constraint: ">= 5",
},
}
for _, err := range businessErrors {
fmt.Printf(" 业务规则违反: %v\\n", err)
}
// 集成错误处理
fmt.Printf(" 集成错误处理:\\n")
integrationErr := &IntegrationError{
Service: "支付服务",
Endpoint: "https://pay.example.com/api/charge",
Method: "POST",
StatusCode: 503,
Message: "服务不可用",
RetryAfter: 30 * time.Second,
Recoverable: true,
}
fmt.Printf(" 集成错误: %v\\n", integrationErr)
fmt.Printf(" 可恢复: %t\\n", integrationErr.Recoverable)
fmt.Printf(" 重试间隔: %v\\n", integrationErr.RetryAfter)
fmt.Println()
}
// ========== 自定义错误类型定义 ==========
// SimpleError 简单自定义错误
type SimpleError struct {
Message string
}
func (e *SimpleError) Error() string {
return e.Message
}
// CodeError 带代码的错误
type CodeError struct {
Code int
Message string
}
func (e *CodeError) Error() string {
return fmt.Sprintf("[%d] %s", e.Code, e.Message)
}
// TimestampError 带时间戳的错误
type TimestampError struct {
Message string
Timestamp time.Time
}
func (e *TimestampError) Error() string {
return fmt.Sprintf("%s (发生时间: %s)", e.Message, e.Timestamp.Format("2006-01-02 15:04:05"))
}
// ContextError 带上下文的错误
type ContextError struct {
Operation string
Resource string
Message string
}
func (e *ContextError) Error() string {
return fmt.Sprintf("操作 '%s' 在资源 '%s' 上失败: %s", e.Operation, e.Resource, e.Message)
}
// ValidationError 验证错误
type ValidationError struct {
Field string
Value string
Rule string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("字段 '%s' 验证失败 (值: '%s', 规则: %s): %s",
e.Field, e.Value, e.Rule, e.Message)
}
// HTTPError HTTP错误
type HTTPError struct {
StatusCode int
Method string
URL string
Message string
}
func (e *HTTPError) Error() string {
return fmt.Sprintf("HTTP %d: %s %s - %s", e.StatusCode, e.Method, e.URL, e.Message)
}
func (e *HTTPError) IsClientError() bool {
return e.StatusCode >= 400 && e.StatusCode < 500
}
func (e *HTTPError) IsServerError() bool {
return e.StatusCode >= 500 && e.StatusCode < 600
}
// DatabaseError 数据库错误
type DatabaseError struct {
Operation string
Table string
Query string
SQLState string
Message string
}
func (e *DatabaseError) Error() string {
return fmt.Sprintf("数据库错误 [%s]: %s 操作在表 '%s' 上失败 - %s",
e.SQLState, e.Operation, e.Table, e.Message)
}
func (e *DatabaseError) IsConstraintViolation() bool {
return strings.HasPrefix(e.SQLState, "23")
}
// BusinessError 业务逻辑错误
type BusinessError struct {
Domain string
Rule string
Message string
Severity string
Retryable bool
}
func (e *BusinessError) Error() string {
return fmt.Sprintf("业务错误 [%s]: 规则 '%s' 违反 - %s", e.Domain, e.Rule, e.Message)
}
// TemporaryError 临时错误
type TemporaryError struct {
Message string
Temporary bool
RetryAfter time.Duration
}
func (e *TemporaryError) Error() string {
return e.Message
}
func (e *TemporaryError) IsTemporary() bool {
return e.Temporary
}
// PermanentError 永久错误
type PermanentError struct {
Message string
Reason string
}
func (e *PermanentError) Error() string {
return fmt.Sprintf("%s (原因: %s)", e.Message, e.Reason)
}
func (e *PermanentError) IsTemporary() bool {
return false
}
// RecoverableError 可恢复错误
type RecoverableError struct {
Message string
RecoveryHint string
}
func (e *RecoverableError) Error() string {
return e.Message
}
// FatalError 致命错误
type FatalError struct {
Message string
Cause string
}
func (e *FatalError) Error() string {
return fmt.Sprintf("致命错误: %s (原因: %s)", e.Message, e.Cause)
}
// UserError 用户错误
type UserError struct {
Message string
UserMessage string
Field string
}
func (e *UserError) Error() string {
return e.Message
}
// SystemError 系统错误
type SystemError struct {
Message string
Component string
Level string
}
func (e *SystemError) Error() string {
return fmt.Sprintf("系统错误 [%s/%s]: %s", e.Component, e.Level, e.Message)
}
// BaseError 基础错误
type BaseError struct {
Code string
Message string
Timestamp time.Time
}
func (e *BaseError) Error() string {
return fmt.Sprintf("[%s] %s", e.Code, e.Message)
}
// NetworkError 网络错误
type NetworkError struct {
BaseError
Host string
Port int
Timeout time.Duration
}
func (e *NetworkError) Error() string {
return fmt.Sprintf("网络错误 [%s]: 连接 %s:%d 失败 - %s (超时: %v)",
e.Code, e.Host, e.Port, e.Message, e.Timeout)
}
// ApplicationError 应用错误
type ApplicationError struct {
BaseError
Module string
Version string
Stack []string
}
func (e *ApplicationError) Error() string {
return fmt.Sprintf("应用错误 [%s]: 模块 '%s' v%s - %s",
e.Code, e.Module, e.Version, e.Message)
}
// ServiceError 服务错误
type ServiceError struct {
BaseError
Service string
Cause error
}
func (e *ServiceError) Error() string {
if e.Cause != nil {
return fmt.Sprintf("服务错误 [%s]: 服务 '%s' - %s (原因: %v)",
e.Code, e.Service, e.Message, e.Cause)
}
return fmt.Sprintf("服务错误 [%s]: 服务 '%s' - %s", e.Code, e.Service, e.Message)
}
func (e *ServiceError) Unwrap() error {
return e.Cause
}
// APIError API错误
type APIError struct {
BaseError
Endpoint string
Cause error
}
func (e *APIError) Error() string {
if e.Cause != nil {
return fmt.Sprintf("API错误 [%s]: 端点 '%s' - %s (原因: %v)",
e.Code, e.Endpoint, e.Message, e.Cause)
}
return fmt.Sprintf("API错误 [%s]: 端点 '%s' - %s", e.Code, e.Endpoint, e.Message)
}
func (e *APIError) Unwrap() error {
return e.Cause
}
// DetailedError 带详细信息的错误
type DetailedError struct {
Code string
Message string
Details map[string]interface{}
}
func (e *DetailedError) Error() string {
return fmt.Sprintf("[%s] %s", e.Code, e.Message)
}
// ErrorMetadata 错误元数据
type ErrorMetadata struct {
RequestID string `json:"request_id"`
UserID string `json:"user_id"`
SessionID string `json:"session_id"`
TraceID string `json:"trace_id"`
Environment string `json:"environment"`
Version string `json:"version"`
}
// MetadataError 带元数据的错误
type MetadataError struct {
Message string
Metadata ErrorMetadata
}
func (e *MetadataError) Error() string {
return fmt.Sprintf("%s [请求ID: %s]", e.Message, e.Metadata.RequestID)
}
// SuggestedError 带建议的错误
type SuggestedError struct {
Message string
Suggestions []string
HelpURL string
}
func (e *SuggestedError) Error() string {
return e.Message
}
// SerializableError 可序列化错误
type SerializableError struct {
Code string `json:"code"`
Message string `json:"message"`
Timestamp time.Time `json:"timestamp"`
Details map[string]interface{} `json:"details,omitempty"`
}
func (e *SerializableError) Error() string {
return fmt.Sprintf("[%s] %s", e.Code, e.Message)
}
// TransportError 传输错误
type TransportError struct {
ID string `json:"id"`
Type string `json:"type"`
Message string `json:"message"`
Code int `json:"code"`
Timestamp int64 `json:"timestamp"`
Data map[string]interface{} `json:"data,omitempty"`
}
func (e *TransportError) Error() string {
return fmt.Sprintf("[%s] %s: %s", e.ID, e.Type, e.Message)
}
// LocalizedError 本地化错误
type LocalizedError struct {
Code string
Message string
Locale string
Translations map[string]string
}
func (e *LocalizedError) Error() string {
return e.Message
}
func (e *LocalizedError) GetMessage(locale string) string {
if msg, ok := e.Translations[locale]; ok {
return msg
}
return e.Message // 返回默认消息
}
// FileError 文件错误
type FileError struct {
Operation string
Path string
Message string
OSError string
}
func (e *FileError) Error() string {
return fmt.Sprintf("文件操作 '%s' 在路径 '%s' 失败: %s (%s)",
e.Operation, e.Path, e.Message, e.OSError)
}
// BusinessRuleError 业务规则错误
type BusinessRuleError struct {
Rule string
Description string
Value string
Constraint string
}
func (e *BusinessRuleError) Error() string {
return fmt.Sprintf("业务规则 '%s' 违反: %s (值: %s, 约束: %s)",
e.Rule, e.Description, e.Value, e.Constraint)
}
// IntegrationError 集成错误
type IntegrationError struct {
Service string
Endpoint string
Method string
StatusCode int
Message string
RetryAfter time.Duration
Recoverable bool
}
func (e *IntegrationError) Error() string {
return fmt.Sprintf("集成错误: %s %s %s 返回 %d - %s",
e.Service, e.Method, e.Endpoint, e.StatusCode, e.Message)
}
// ========== 辅助函数 ==========
// printErrorChain 打印错误链
func printErrorChain(err error, indent string) {
if err == nil {
return
}
fmt.Printf("%s- %v\\n", indent, err)
// 检查是否有 Unwrap 方法
if unwrapper, ok := err.(interface{ Unwrap() error }); ok {
if cause := unwrapper.Unwrap(); cause != nil {
printErrorChain(cause, indent+" ")
}
}
}
// transmitError 模拟错误传输
func transmitError(err *TransportError) *TransportError {
// 模拟网络传输过程
return &TransportError{
ID: err.ID,
Type: err.Type,
Message: err.Message,
Code: err.Code,
Timestamp: err.Timestamp,
Data: err.Data,
}
}
// handleAPIError 处理API错误
func handleAPIError(err error) {
if apiErr, ok := err.(*APIError); ok {
switch apiErr.Code {
case "AUTH001":
fmt.Printf(" 认证错误,需要重新登录\\n")
case "RATE001":
fmt.Printf(" 请求频率超限,需要等待\\n")
case "VAL001":
fmt.Printf(" 参数验证失败,检查输入\\n")
default:
fmt.Printf(" 未知API错误: %v\\n", apiErr)
}
}
}
// handleDatabaseError 处理数据库错误
func handleDatabaseError(err error) {
if dbErr, ok := err.(*DatabaseError); ok {
switch {
case strings.HasPrefix(dbErr.SQLState, "42"):
fmt.Printf(" SQL语法错误: %v\\n", dbErr)
case strings.HasPrefix(dbErr.SQLState, "23"):
fmt.Printf(" 约束违反错误: %v\\n", dbErr)
case strings.HasPrefix(dbErr.SQLState, "40"):
fmt.Printf(" 事务错误: %v\\n", dbErr)
default:
fmt.Printf(" 其他数据库错误: %v\\n", dbErr)
}
}
}
// handleFileError 处理文件错误
func handleFileError(err *FileError) {
fmt.Printf(" 文件错误: %v\\n", err)
switch err.Operation {
case "read":
fmt.Printf(" 建议: 检查文件是否存在和读取权限\\n")
case "write":
fmt.Printf(" 建议: 检查目录写入权限和磁盘空间\\n")
case "delete":
fmt.Printf(" 建议: 检查文件是否被其他程序占用\\n")
}
}
/*
运行这个程序:
go run 02-custom-errors.go
学习要点:
1. 自定义错误类型通过实现 error 接口来创建
2. 自定义错误可以包含更多的上下文信息
3. 错误可以按照不同的维度进行分类
4. 错误层次结构有助于组织和处理复杂的错误情况
5. 错误的序列化和本地化对于分布式系统很重要
自定义错误的优势:
1. 提供更多的上下文信息
2. 支持错误分类和层次结构
3. 便于错误处理和恢复
4. 支持错误的序列化和传输
5. 提供更好的用户体验
错误设计原则:
1. 错误信息应该清晰、准确
2. 包含足够的上下文信息
3. 支持错误的分类和处理
4. 考虑错误的传播和包装
5. 提供恢复建议和帮助信息
错误分类维度:
1. 临时性:临时错误 vs 永久错误
2. 可恢复性:可恢复错误 vs 不可恢复错误
3. 责任方:用户错误 vs 系统错误
4. 严重程度:警告 vs 错误 vs 致命错误
5. 来源:网络错误 vs 数据库错误 vs 业务错误
错误层次结构:
1. 基础错误:定义通用的错误属性
2. 分类错误:按照错误类型分类
3. 具体错误:特定场景的错误实现
4. 错误链:支持错误的嵌套和包装
5. 错误接口:定义错误的行为
实际应用考虑:
1. 错误码的设计和管理
2. 错误信息的国际化
3. 错误的日志记录
4. 错误的监控和告警
5. 错误的用户友好展示
最佳实践:
1. 为不同的错误场景定义专门的错误类型
2. 在错误中包含足够的上下文信息
3. 支持错误的包装和解包
4. 提供错误的分类和判断方法
5. 考虑错误的序列化和传输需求
注意事项:
1. 避免错误信息中包含敏感信息
2. 错误类型不要过于复杂
3. 保持错误接口的一致性
4. 考虑错误的性能影响
5. 提供适当的错误恢复机制
*/