Best Practices - zhoudm1743/go-util GitHub Wiki

本指南汇总了 Go-Util 在实际项目中的最佳实践,帮助您写出更高效、更可维护的代码。

🎯 核心原则

1. 类型安全优先

// ✅ 推荐:使用泛型确保类型安全
numbers := util.Arrays(1, 2, 3, 4, 5)  // XArray[int]
result := numbers.Filter(func(n int) bool {
    return n > 3
}).Map(func(n int) string {
    return fmt.Sprintf("num_%d", n)
})

// ❌ 避免:使用 interface{} 丢失类型信息
mixed := util.NewArray[interface{}]()
mixed.Append(1, "hello", 3.14)  // 类型不一致,容易出错

2. 链式调用的合理使用

// ✅ 推荐:合理的链式调用(3-5个方法)
result := util.Str(userInput).
    Trim().                    // 步骤1:去除空白
    Lower().                   // 步骤2:转为小写
    ReplaceRegex(`\s+`, "_").  // 步骤3:空格替换为下划线
    String()

// ❌ 避免:过长的链式调用(影响可读性和调试)
result := util.Str(input).Trim().Lower().ReplaceRegex(`\s+`, "_").
    Snake2Camel().FirstUpper().HTMLEscape().Truncate(100).Base64Encode().String()

// ✅ 推荐:分步骤处理复杂逻辑
cleaned := util.Str(userInput).Trim().Lower().String()
formatted := util.Str(cleaned).ReplaceRegex(`\s+`, "_").Snake2Camel().String()
final := util.Str(formatted).FirstUpper().HTMLEscape().String()

3. 性能优先策略

// ✅ 推荐:预分配容量
expectedSize := 10000
arr := util.NewArrayWithCapacity[int](expectedSize)
m := util.NewMapWithCapacity[string, int](expectedSize)

// ✅ 推荐:使用原地操作
arr.FilterInPlace(condition)
arr.SortInPlace()

// ✅ 推荐:批量操作
data := map[string]int{"key1": 1, "key2": 2, "key3": 3}
m.SetBatch(data)

// ❌ 避免:频繁的小操作
for key, value := range largeDataSet {
    smallArray := util.Arrays(value)  // 每次都创建新数组
    // 处理...
}

📊 数据处理最佳实践

XArray 数组处理

1. 函数式编程风格

// ✅ 推荐:使用语义化的函数名
isValidUser := func(u User) bool {
    return u.Email != "" && u.Age >= 18
}

transformToDTO := func(u User) UserDTO {
    return UserDTO{
        ID:   u.ID,
        Name: u.Name,
        Age:  u.Age,
    }
}

// 清晰的数据处理管道
validUsers := util.ArraysFromSlice(users).
    Filter(isValidUser).           // 过滤有效用户
    Map(transformToDTO).           // 转换为DTO
    SortBy(func(dto UserDTO) string {
        return dto.Name            // 按姓名排序
    }).
    ToSlice()

2. 错误处理模式

// ✅ 推荐:使用 Result 模式处理可能失败的操作
type ProcessResult struct {
    Data  []ProcessedItem
    Errors []ProcessError
}

func ProcessItems(items []RawItem) ProcessResult {
    var results []ProcessedItem
    var errors []ProcessError
    
    util.ArraysFromSlice(items).ForEach(func(i int, item RawItem) bool {
        if processed, err := processItem(item); err != nil {
            errors = append(errors, ProcessError{Index: i, Error: err})
        } else {
            results = append(results, processed)
        }
        return true
    })
    
    return ProcessResult{Data: results, Errors: errors}
}

3. 内存管理策略

// ✅ 推荐:大数据集分块处理
func ProcessLargeDataset(data []LargeItem) []ProcessedItem {
    const chunkSize = 1000
    var results []ProcessedItem
    
    for i := 0; i < len(data); i += chunkSize {
        end := i + chunkSize
        if end > len(data) {
            end = len(data)
        }
        
        chunk := data[i:end]
        processed := util.ArraysFromSlice(chunk).
            ParallelMap(processItem, runtime.NumCPU()).
            ToSlice()
        
        results = append(results, processed...)
        
        // 强制垃圾回收,释放内存
        runtime.GC()
    }
    
    return results
}

XMap 映射处理

1. 配置管理模式

// ✅ 推荐:类型安全的配置管理
type AppConfig struct {
    Database *util.XMap[string, string]
    Cache    *util.XMap[string, interface{}]
    Features *util.XMap[string, bool]
}

func LoadConfig(configFile string) (*AppConfig, error) {
    data, err := os.ReadFile(configFile)
    if err != nil {
        return nil, err
    }
    
    var rawConfig map[string]interface{}
    if err := json.Unmarshal(data, &rawConfig); err != nil {
        return nil, err
    }
    
    config := &AppConfig{
        Database: util.NewMap[string, string](),
        Cache:    util.NewMap[string, interface{}](),
        Features: util.NewMap[string, bool](),
    }
    
    // 类型安全的配置解析
    if dbConfig, ok := rawConfig["database"].(map[string]interface{}); ok {
        for key, value := range dbConfig {
            if strValue, ok := value.(string); ok {
                config.Database.Set(key, strValue)
            }
        }
    }
    
    return config, nil
}

2. 缓存策略

// ✅ 推荐:使用过期缓存
type CacheManager struct {
    cache *util.ExpiringMap[string, interface{}]
    mutex sync.RWMutex
}

func NewCacheManager(defaultTTL time.Duration) *CacheManager {
    return &CacheManager{
        cache: util.NewExpiringMap[string, interface{}](defaultTTL),
    }
}

func (cm *CacheManager) GetOrSet(key string, factory func() (interface{}, error)) (interface{}, error) {
    cm.mutex.RLock()
    if value, exists := cm.cache.Get(key); exists {
        cm.mutex.RUnlock()
        return value, nil
    }
    cm.mutex.RUnlock()
    
    cm.mutex.Lock()
    defer cm.mutex.Unlock()
    
    // 双重检查锁定
    if value, exists := cm.cache.Get(key); exists {
        return value, nil
    }
    
    value, err := factory()
    if err != nil {
        return nil, err
    }
    
    cm.cache.Set(key, value)
    return value, nil
}

XTime 时间处理

1. 时区最佳实践

// ✅ 推荐:统一使用 UTC 存储,本地时区显示
type Event struct {
    ID        string
    Name      string
    StartTime *util.XTime  // 始终存储为 UTC
}

func (e *Event) Save() error {
    // 确保存储为 UTC
    e.StartTime = e.StartTime.ToUTC()
    return database.Save(e)
}

func (e *Event) DisplayTime(userTimezone string) string {
    // 根据用户时区显示
    localTime := e.StartTime.InTimezone(userTimezone)
    return localTime.FormatCustom("2006-01-02 15:04 MST")
}

// ✅ 推荐:时区感知的业务逻辑
func IsBusinessHours(timezone string) bool {
    localTime := util.Now().InTimezone(timezone)
    
    // 业务时间:周一至周五 9:00-18:00
    if localTime.IsWeekend() {
        return false
    }
    
    hour := localTime.Hour()
    return hour >= 9 && hour < 18
}

2. 性能优化模式

// ✅ 推荐:使用时间缓存减少系统调用
var timeCache = util.NewTimeCache(time.Second)

func GetCurrentTimestamp() int64 {
    return timeCache.Now().Timestamp()
}

// ✅ 推荐:批量时间操作
func FormatBatchTimes(times []*util.XTime, format string) []string {
    return util.ArraysFromSlice(times).
        Map(func(t *util.XTime) string {
            return t.FormatCustom(format)
        }).
        ToSlice()
}

🔒 安全最佳实践

1. 输入验证和清理

// ✅ 推荐:输入验证管道
func ValidateAndCleanUserInput(input string) (string, error) {
    // 步骤1:基础验证
    if util.Str(input).IsBlank() {
        return "", errors.New("输入不能为空")
    }
    
    // 步骤2:长度限制
    if util.Str(input).Len() > 1000 {
        return "", errors.New("输入长度超过限制")
    }
    
    // 步骤3:清理和转义
    cleaned := util.Str(input).
        Trim().                    // 去除首尾空白
        ReplaceRegex(`\s+`, " ").  // 规范化空格
        HTMLEscape().              // HTML 转义
        String()
    
    // 步骤4:内容验证
    if !util.Str(cleaned).MatchRegex(`^[a-zA-Z0-9\s\-_.@]+$`) {
        return "", errors.New("输入包含非法字符")
    }
    
    return cleaned, nil
}

2. 敏感数据处理

// ✅ 推荐:敏感数据脱敏
func MaskSensitiveData(data map[string]interface{}) map[string]interface{} {
    sensitiveFields := util.Arrays("password", "ssn", "credit_card", "api_key")
    
    return util.MapFromNative(data).
        MapValues(func(value interface{}) interface{} {
            if str, ok := value.(string); ok {
                // 脱敏处理
                if len(str) > 4 {
                    return str[:2] + "****" + str[len(str)-2:]
                }
                return "****"
            }
            return value
        }).
        Filter(func(key string, value interface{}) bool {
            // 过滤敏感字段
            return !sensitiveFields.Contains(strings.ToLower(key))
        }).
        ToMap()
}

🧪 测试最佳实践

1. 单元测试模式

// ✅ 推荐:使用表驱动测试
func TestStringValidation(t *testing.T) {
    testCases := []struct {
        name     string
        input    string
        expected bool
    }{
        {"valid email", "[email protected]", true},
        {"invalid email", "invalid-email", false},
        {"empty string", "", false},
        {"valid phone", "13812345678", true},
    }
    
    for _, tc := range testCases {
        t.Run(tc.name, func(t *testing.T) {
            result := util.Str(tc.input).IsEmail()
            if result != tc.expected {
                t.Errorf("Expected %v, got %v for input %s", tc.expected, result, tc.input)
            }
        })
    }
}

2. 基准测试

// ✅ 推荐:性能基准测试
func BenchmarkArrayOperations(b *testing.B) {
    data := make([]int, 10000)
    for i := range data {
        data[i] = rand.Intn(1000)
    }
    
    b.ResetTimer()
    b.ReportAllocs()
    
    for i := 0; i < b.N; i++ {
        result := util.ArraysFromSlice(data).
            Filter(func(n int) bool { return n%2 == 0 }).
            Map(func(n int) int { return n * 2 }).
            ToSlice()
        _ = result
    }
}

📝 代码风格指南

1. 命名约定

// ✅ 推荐:语义化的变量名
userEmails := util.ArraysFromSlice(users).
    Map(func(u User) string { return u.Email })

activeUserCount := users.Count(func(u User) bool { 
    return u.IsActive 
})

// ✅ 推荐:描述性的函数名
isValidEmailFormat := func(email string) bool {
    return util.Str(email).IsEmail()
}

transformUserToDTO := func(u User) UserDTO {
    return UserDTO{ID: u.ID, Name: u.Name}
}

2. 错误处理

// ✅ 推荐:详细的错误信息
func ProcessUserData(users []User) ([]ProcessedUser, error) {
    if len(users) == 0 {
        return nil, fmt.Errorf("用户列表不能为空")
    }
    
    results := make([]ProcessedUser, 0, len(users))
    
    for i, user := range users {
        if util.Str(user.Email).IsBlank() {
            return nil, fmt.Errorf("用户 #%d 的邮箱不能为空", i+1)
        }
        
        processed, err := processUser(user)
        if err != nil {
            return nil, fmt.Errorf("处理用户 %s 失败: %w", user.Email, err)
        }
        
        results = append(results, processed)
    }
    
    return results, nil
}

🚀 性能优化指南

1. 内存管理

// ✅ 推荐:对象池模式
var arrayPool = sync.Pool{
    New: func() interface{} {
        return util.NewArrayWithCapacity[string](100)
    },
}

func ProcessStrings(input []string) []string {
    arr := arrayPool.Get().(*util.XArray[string])
    defer func() {
        arr.Clear()
        arrayPool.Put(arr)
    }()
    
    // 处理逻辑...
    return arr.ToSlice()
}

2. 并发处理

// ✅ 推荐:合理使用并发
func ProcessLargeDataset(data []Item) []Result {
    const minChunkSize = 1000
    workerCount := runtime.NumCPU()
    
    if len(data) < minChunkSize {
        // 小数据集直接处理
        return util.ArraysFromSlice(data).
            Map(processItem).
            ToSlice()
    }
    
    // 大数据集并发处理
    return util.ArraysFromSlice(data).
        ParallelMap(processItem, workerCount).
        ToSlice()
}

📋 代码审查清单

✅ 性能检查

  • 是否预分配了容量?
  • 是否使用了原地操作?
  • 是否避免了不必要的内存分配?
  • 是否使用了适当的并发策略?

✅ 安全检查

  • 输入是否经过验证和清理?
  • 敏感数据是否得到适当处理?
  • 是否避免了XSS和注入攻击?
  • 错误信息是否泄露了敏感信息?

✅ 可维护性检查

  • 函数名是否语义化?
  • 链式调用是否合理?
  • 错误处理是否完善?
  • 代码是否有适当的注释?

✅ 测试检查

  • 是否有单元测试覆盖?
  • 是否有边界条件测试?
  • 是否有性能基准测试?
  • 测试用例是否充分?

🎨 设计模式应用

1. 建造者模式

// ✅ 推荐:使用建造者模式构建复杂对象
type ReportBuilder struct {
    data    *util.XArray[ReportItem]
    filters []FilterFunc
    sorters []SortFunc
}

func NewReportBuilder() *ReportBuilder {
    return &ReportBuilder{
        data: util.NewArray[ReportItem](),
    }
}

func (rb *ReportBuilder) AddData(items []ReportItem) *ReportBuilder {
    rb.data.AppendSlice(items)
    return rb
}

func (rb *ReportBuilder) AddFilter(filter FilterFunc) *ReportBuilder {
    rb.filters = append(rb.filters, filter)
    return rb
}

func (rb *ReportBuilder) Build() *Report {
    result := rb.data.Clone()
    
    // 应用过滤器
    for _, filter := range rb.filters {
        result = result.Filter(filter)
    }
    
    // 应用排序
    for _, sorter := range rb.sorters {
        result = result.SortWith(sorter)
    }
    
    return &Report{Data: result.ToSlice()}
}

2. 策略模式

// ✅ 推荐:使用策略模式处理不同的数据源
type DataProcessor interface {
    Process(data *util.XArray[RawData]) *util.XArray[ProcessedData]
}

type CSVProcessor struct{}
func (p CSVProcessor) Process(data *util.XArray[RawData]) *util.XArray[ProcessedData] {
    return data.Map(func(raw RawData) ProcessedData {
        // CSV 特定处理逻辑
        return ProcessedData{}
    })
}

type JSONProcessor struct{}
func (p JSONProcessor) Process(data *util.XArray[RawData]) *util.XArray[ProcessedData] {
    return data.Map(func(raw RawData) ProcessedData {
        // JSON 特定处理逻辑
        return ProcessedData{}
    })
}

func ProcessDataWithStrategy(data *util.XArray[RawData], processor DataProcessor) *util.XArray[ProcessedData] {
    return processor.Process(data)
}

📚 学习资源

推荐阅读

实践建议

  1. 从小项目开始:在小项目中实践这些最佳实践
  2. 逐步优化:不要一次性应用所有优化,逐步改进
  3. 性能测试:定期进行性能基准测试
  4. 代码审查:使用提供的清单进行代码审查
  5. 持续学习:关注社区最佳实践的更新

💬 获取帮助

如果您在实践中遇到问题:


🎯 遵循这些最佳实践,让您的 Go-Util 代码更加优雅、高效和可维护!