Contributing - zhoudm1743/go-util GitHub Wiki
欢迎为 Go-Util 项目贡献力量!本指南将帮助您了解如何参与项目开发,提交代码,报告问题,以及改进文档。
- 🔧 新功能开发 - 实现新的工具类和方法
- 🐛 Bug 修复 - 修复已知问题和缺陷
- ⚡ 性能优化 - 提升现有功能的性能
- 🧪 测试完善 - 增加单元测试和集成测试
- 📝 API 文档 - 完善函数和方法的文档说明
- 📚 使用指南 - 编写教程和最佳实践
- 🌍 多语言支持 - 翻译文档到其他语言
- 💡 示例代码 - 提供实用的代码示例
- 💬 问题解答 - 帮助其他用户解决问题
- 🔍 问题报告 - 发现并报告 bug
- 💡 功能建议 - 提出新功能和改进建议
- 📢 推广分享 - 在社区分享使用经验
# 1. Fork 项目到您的 GitHub 账户
# 2. 克隆项目到本地
git clone https://github.com/your-username/go-util.git
cd go-util
# 3. 添加上游仓库
git remote add upstream https://github.com/zhoudm1743/go-util.git
# 4. 安装 Go(版本 >= 1.19)
go version
# 5. 安装依赖
go mod download
# 6. 运行测试确保环境正常
go test ./...
# 1. 创建功能分支
git checkout -b feature/your-feature-name
# 2. 进行开发
# ... 编写代码 ...
# 3. 运行测试
go test ./...
# 4. 运行代码检查
go vet ./...
go fmt ./...
# 5. 提交更改
git add .
git commit -m "feat: 添加新功能说明"
# 6. 推送到您的仓库
git push origin feature/your-feature-name
# 7. 创建 Pull Request
// ✅ 推荐:使用语义化的函数名
func ProcessUserData(users []User) []ProcessedUser {
return util.ArraysFromSlice(users).
Filter(isValidUser).
Map(transformUser).
ToSlice()
}
// ✅ 推荐:接口名使用 -er 后缀
type DataProcessor interface {
Process(data []byte) ([]byte, error)
}
// ✅ 推荐:包名简短且有意义
package stringutils // 而不是 strutils 或 string_utilities
// ✅ 推荐:常量使用大写
const (
DefaultTimeout = 30 * time.Second
MaxRetries = 3
)
// ✅ 推荐:文件组织结构
// types_str.go - 字符串工具
// types_array.go - 数组工具
// types_map.go - 映射工具
// types_time.go - 时间工具
// ✅ 推荐:包内导入顺序
import (
// 标准库
"context"
"fmt"
"time"
// 第三方库
"github.com/example/package"
// 本地导入
"github.com/zhoudm1743/go-util/internal"
)
// ✅ 推荐:结构体字段排序
type User struct {
// 导出字段在前
ID string
Name string
Email string
// 未导出字段在后
password string
lastLogin time.Time
}
// Package util 提供了一套强大的 Go 语言工具库,
// 包含字符串、数组、映射、时间等常用操作的链式API。
//
// 使用示例:
// str := util.Str("hello world").Upper().ReplaceRegex(`\s+`, "_").String()
// // 结果: "HELLO_WORLD"
package util
// XStr 表示一个字符串包装器,提供链式操作方法。
//
// XStr 支持各种字符串操作,包括大小写转换、格式验证、
// 内容替换、编码解码等功能。
//
// 使用示例:
// email := util.Str(userInput).Trim().Lower().String()
// if util.Str(email).IsEmail() {
// // 处理有效邮箱
// }
type XStr struct {
value string
}
// Upper 将字符串转换为大写。
//
// 返回一个新的 XStr 实例,原实例保持不变。
//
// 使用示例:
// result := util.Str("hello").Upper().String() // "HELLO"
func (s *XStr) Upper() *XStr {
return &XStr{value: strings.ToUpper(s.value)}
}
// IsEmail 检查字符串是否为有效的邮箱地址。
//
// 使用正则表达式验证邮箱格式的有效性。
//
// 返回值:
// - true: 字符串是有效的邮箱地址
// - false: 字符串不是有效的邮箱地址
//
// 使用示例:
// valid := util.Str("[email protected]").IsEmail() // true
// invalid := util.Str("not-an-email").IsEmail() // false
func (s *XStr) IsEmail() bool {
pattern := `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`
matched, _ := regexp.MatchString(pattern, s.value)
return matched
}
// ✅ 推荐:定义自定义错误类型
type ValidationError struct {
Field string
Value interface{}
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("字段 %s 验证失败: %s (值: %v)", e.Field, e.Message, e.Value)
}
// ✅ 推荐:使用 errors.Is 和 errors.As
func ProcessData(data string) error {
if err := validateData(data); err != nil {
var validationErr *ValidationError
if errors.As(err, &validationErr) {
// 处理验证错误
return fmt.Errorf("数据处理失败: %w", err)
}
return err
}
return nil
}
// ✅ 推荐:链式操作中的错误处理
func (s *XStr) SafeToInt() (int, error) {
if s.IsBlank() {
return 0, errors.New("不能将空字符串转换为整数")
}
value, err := strconv.Atoi(s.value)
if err != nil {
return 0, fmt.Errorf("字符串转整数失败: %w", err)
}
return value, nil
}
// ✅ 推荐:测试文件命名 *_test.go
// types_str_test.go
func TestXStr_Upper(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{
name: "基础大写转换",
input: "hello",
expected: "HELLO",
},
{
name: "混合字符",
input: "Hello World",
expected: "HELLO WORLD",
},
{
name: "空字符串",
input: "",
expected: "",
},
{
name: "已经是大写",
input: "HELLO",
expected: "HELLO",
},
{
name: "包含数字和特殊字符",
input: "hello123!@#",
expected: "HELLO123!@#",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := util.Str(tt.input).Upper().String()
if result != tt.expected {
t.Errorf("Upper() = %v, want %v", result, tt.expected)
}
})
}
}
// ✅ 推荐:边界条件测试
func TestXStr_IsEmail_EdgeCases(t *testing.T) {
testCases := []struct {
email string
expected bool
reason string
}{
{"", false, "空字符串"},
{"@", false, "只有@符号"},
{"user@", false, "缺少域名"},
{"@domain.com", false, "缺少用户名"},
{"user@domain", false, "缺少顶级域名"},
{"[email protected]", true, "用户名包含点"},
{"[email protected]", true, "用户名包含加号"},
{"[email protected]", true, "长邮箱地址"},
}
for _, tc := range testCases {
t.Run(tc.reason, func(t *testing.T) {
result := util.Str(tc.email).IsEmail()
if result != tc.expected {
t.Errorf("IsEmail(%q) = %v, want %v (%s)",
tc.email, result, tc.expected, tc.reason)
}
})
}
}
// ✅ 推荐:性能基准测试
func BenchmarkXStr_Upper(b *testing.B) {
testStr := "hello world this is a benchmark test"
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = util.Str(testStr).Upper().String()
}
}
func BenchmarkXStr_ChainedOperations(b *testing.B) {
testStr := " hello WORLD [email protected] "
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
result := util.Str(testStr).
Trim().
Lower().
ReplaceRegex(`\s+`, "_").
String()
_ = result
}
}
// ✅ 推荐:内存分配测试
func TestXStr_MemoryAllocation(t *testing.T) {
const iterations = 1000
// 测试链式操作的内存分配
var allocsBefore runtime.MemStats
runtime.ReadMemStats(&allocsBefore)
for i := 0; i < iterations; i++ {
_ = util.Str("test").Upper().Lower().Trim().String()
}
var allocsAfter runtime.MemStats
runtime.ReadMemStats(&allocsAfter)
allocsPerOp := (allocsAfter.Mallocs - allocsBefore.Mallocs) / iterations
// 确保每次操作的内存分配在合理范围内
if allocsPerOp > 10 {
t.Errorf("过多的内存分配: %d allocs/op", allocsPerOp)
}
}
// ✅ 推荐:功能集成测试
func TestUserDataProcessingIntegration(t *testing.T) {
// 模拟真实的用户数据处理场景
rawUsers := []map[string]interface{}{
{"name": " Alice ", "email": "[email protected]", "age": "25"},
{"name": "Bob", "email": "[email protected]", "age": "30"},
{"name": "", "email": "invalid-email", "age": "abc"},
}
var processedUsers []User
var errors []error
for i, rawUser := range rawUsers {
// 使用 Go-Util 处理用户数据
name := util.Str(fmt.Sprintf("%v", rawUser["name"])).Trim().String()
email := util.Str(fmt.Sprintf("%v", rawUser["email"])).Lower().Trim().String()
ageStr := util.Str(fmt.Sprintf("%v", rawUser["age"])).Trim().String()
// 验证数据
if util.Str(name).IsBlank() {
errors = append(errors, fmt.Errorf("用户 %d: 姓名不能为空", i))
continue
}
if !util.Str(email).IsEmail() {
errors = append(errors, fmt.Errorf("用户 %d: 邮箱格式无效", i))
continue
}
if !util.Str(ageStr).IsNumeric() {
errors = append(errors, fmt.Errorf("用户 %d: 年龄必须为数字", i))
continue
}
age := util.Str(ageStr).Int()
processedUsers = append(processedUsers, User{
Name: name,
Email: email,
Age: age,
})
}
// 验证结果
if len(processedUsers) != 2 {
t.Errorf("期望处理2个用户,实际处理了%d个", len(processedUsers))
}
if len(errors) != 1 {
t.Errorf("期望1个错误,实际有%d个错误", len(errors))
}
// 验证处理后的数据
alice := processedUsers[0]
if alice.Name != "Alice" || alice.Email != "[email protected]" || alice.Age != 25 {
t.Errorf("Alice 数据处理错误: %+v", alice)
}
}
<type>(<scope>): <description>
[optional body]
[optional footer(s)]
-
feat
: 新功能 -
fix
: Bug 修复 -
docs
: 文档更新 -
style
: 代码格式化(不影响功能) -
refactor
: 代码重构 -
perf
: 性能优化 -
test
: 测试相关 -
chore
: 构建过程或辅助工具的变动
# 新功能
git commit -m "feat(str): 添加 IsPhoneNumber 方法用于验证手机号"
# Bug 修复
git commit -m "fix(array): 修复 ParallelMap 在空数组时的 panic 问题"
# 文档更新
git commit -m "docs(readme): 更新安装说明和使用示例"
# 性能优化
git commit -m "perf(map): 优化 MergeWith 方法的内存分配"
# 重构
git commit -m "refactor(time): 重构时区处理逻辑提高可读性"
[Type] Brief description
## 📋 变更类型
- [ ] 新功能 (feat)
- [ ] Bug 修复 (fix)
- [ ] 文档更新 (docs)
- [ ] 性能优化 (perf)
- [ ] 代码重构 (refactor)
- [ ] 测试相关 (test)
## 📝 变更描述
简要描述本次变更的内容和目的。
## 🔧 具体变更
- 添加了 XStr.IsPhoneNumber() 方法
- 支持中国大陆手机号格式验证
- 添加了相应的单元测试
## 🧪 测试
- [ ] 添加了单元测试
- [ ] 添加了基准测试
- [ ] 现有测试全部通过
- [ ] 测试覆盖率 >= 80%
## 📚 文档
- [ ] 更新了 API 文档
- [ ] 更新了使用示例
- [ ] 更新了 README
## ✅ 检查清单
- [ ] 代码符合项目规范
- [ ] 没有引入 breaking changes
- [ ] 性能没有明显下降
- [ ] 代码经过了 `go fmt` 格式化
- [ ] 代码通过了 `go vet` 检查
## 🔗 相关链接
- 关闭 Issue: #123
- 相关 PR: #456
- ✅ 功能是否按预期工作
- ✅ 边界条件是否正确处理
- ✅ 错误处理是否完善
- ✅ 性能是否可接受
- ✅ 代码结构是否清晰
- ✅ 命名是否语义化
- ✅ 注释是否充分
- ✅ 是否遵循项目规范
- ✅ 测试覆盖率是否充足
- ✅ 测试用例是否全面
- ✅ 基准测试是否必要
- ✅ 集成测试是否通过
✅ 好的反馈示例:
建议在第 45 行添加空值检查,避免潜在的 panic:
```go
if input == nil {
return "", errors.New("input cannot be nil")
}
❌ 不好的反馈示例: 这里有问题。
#### 认可好的实现:
```markdown
👍 这个实现很优雅,使用链式调用提高了代码可读性。
💡 很好的性能优化,减少了内存分配。
- 🌱 入门任务: 文档更新、简单 bug 修复
- 📝 学习资源: 提供详细的开发指南
- 🤝 导师支持: 配对有经验的贡献者
- 🔧 中等任务: 新功能开发、性能优化
- 🧪 测试责任: 确保代码质量
- 📋 问题分类: 帮助分类和优先级排序
- 🔑 关键功能: 架构设计、核心模块开发
- 👥 代码审查: 审查其他贡献者的代码
- 📊 项目规划: 参与项目路线图制定
- 🎯 项目方向: 决定项目发展方向
- 🔄 发布管理: 负责版本发布
- 🌐 社区建设: 建设和维护社区
- ✅ 核心工具类完善
- ✅ JSONx 高性能 JSON 操作
- ✅ JWT 零依赖实现
- ✅ XEnum 类型安全枚举
- 🔄 计划中: 数据库 ORM 集成工具
- 🔄 计划中: HTTP 客户端增强
- 🔄 计划中: 缓存抽象层
- 🔄 计划中: 配置管理工具
- 🔮 构想中: 微服务工具套件
- 🔮 构想中: 分布式锁实现
- 🔮 构想中: 消息队列抽象
- 🔮 构想中: 监控和指标收集
我们将在以下地方认可贡献者:
- 📊 GitHub 贡献图: 自动显示代码贡献
- 📝 CONTRIBUTORS.md: 列出所有贡献者
- 🎉 发布说明: 感谢版本贡献者
- 🌟 项目主页: 突出核心贡献者
- 🥇 月度贡献者: 每月最活跃贡献者
- 🏆 年度贡献者: 年度杰出贡献者
- 💎 特殊贡献: 重大功能或修复贡献者
- 🎨 文档大师: 文档质量突出贡献者
- 💬 GitHub Discussions: 项目讨论区
- 🐛 GitHub Issues: 问题报告
- 📧 邮件联系: [email protected]
- 💬 开发者群组: 加入开发者交流群
- 📺 在线会议: 每月贡献者会议
- 📚 知识库: 查看常见问题解答
通过向本项目贡献代码,您同意您的贡献将在 MIT 许可证下进行许可。
🤝 感谢您对 Go-Util 项目的贡献!每一个贡献都让这个项目变得更好!