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)
}
📚 学习资源
推荐阅读
实践建议
- 从小项目开始:在小项目中实践这些最佳实践
- 逐步优化:不要一次性应用所有优化,逐步改进
- 性能测试:定期进行性能基准测试
- 代码审查:使用提供的清单进行代码审查
- 持续学习:关注社区最佳实践的更新
💬 获取帮助
如果您在实践中遇到问题:
- 🔍 查看FAQ - 常见问题解答
- 🐛 报告问题 - Bug反馈
- 💡 功能建议 - 新功能讨论
- 📧 邮件支持 - [email protected]
🎯 遵循这些最佳实践,让您的 Go-Util 代码更加优雅、高效和可维护!