新增:文档体系重构+CHANGELOG补充+发布产物清理
This commit is contained in:
429
docs/03-模块文档/文件系统/filesystem-code-style-guide.md
Normal file
429
docs/03-模块文档/文件系统/filesystem-code-style-guide.md
Normal file
@@ -0,0 +1,429 @@
|
||||
# 文件管理模块代码风格规范
|
||||
|
||||
## 概述
|
||||
|
||||
本文档定义了文件管理模块的代码风格规范,确保代码一致性、可读性和可维护性。
|
||||
|
||||
---
|
||||
|
||||
## 1. 注释规范
|
||||
|
||||
### 1.1 包注释
|
||||
每个包应该有一个简短的包注释,说明包的用途。
|
||||
|
||||
```go
|
||||
// Package filesystem 提供文件系统操作功能
|
||||
//
|
||||
// 核心功能:
|
||||
// - 文件读写、删除、列表
|
||||
// - 路径验证和安全检查
|
||||
// - ZIP文件操作
|
||||
// - 审计日志和回收站
|
||||
package filesystem
|
||||
```
|
||||
|
||||
### 1.2 函数注释
|
||||
使用标准Go文档注释风格:
|
||||
|
||||
```go
|
||||
// DeletePath 删除文件或目录
|
||||
//
|
||||
// 参数:
|
||||
// path - 文件或目录路径
|
||||
//
|
||||
// 返回:
|
||||
// error - 错误信息,nil表示成功
|
||||
//
|
||||
// 示例:
|
||||
// err := fs.DeletePath("/path/to/file")
|
||||
func (s *FileSystemService) DeletePath(path string) error {
|
||||
// 实现...
|
||||
}
|
||||
```
|
||||
|
||||
### 1.3 禁止的注释风格
|
||||
```go
|
||||
// 禁止使用emoji
|
||||
// 🔒 安全检查
|
||||
// ✅ 优化
|
||||
// ⚠️ 警告
|
||||
|
||||
// 应使用纯文本
|
||||
// 安全检查
|
||||
// 性能优化
|
||||
// 警告
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 错误处理规范
|
||||
|
||||
### 2.1 错误包装
|
||||
使用 WrapError 添加上下文:
|
||||
|
||||
```go
|
||||
// 推荐做法
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", WrapError("读取文件", path, err)
|
||||
}
|
||||
|
||||
// 避免裸错误
|
||||
return "", err // ❌ 不推荐
|
||||
return "", fmt.Errorf("失败: %w", err) // ✅ 推荐
|
||||
```
|
||||
|
||||
### 2.2 错误消息
|
||||
使用中文描述(面向中文用户):
|
||||
|
||||
```go
|
||||
// 推荐
|
||||
return fmt.Errorf("文件不存在: %s", path)
|
||||
|
||||
// 避免使用英文
|
||||
return fmt.Errorf("file not found: %s", path) // ❌
|
||||
```
|
||||
|
||||
### 2.3 错误忽略
|
||||
必须注释说明原因:
|
||||
|
||||
```go
|
||||
// 推荐:注释说明原因
|
||||
if err := logger.Close(); err != nil {
|
||||
// 日志关闭失败,程序即将退出,忽略错误
|
||||
}
|
||||
|
||||
// 禁止:无注释忽略
|
||||
_ = logger.Close() // ❌
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 命名规范
|
||||
|
||||
### 3.1 常量命名
|
||||
使用大驼峰命名法:
|
||||
|
||||
```go
|
||||
const (
|
||||
MaxZipSize = 100 * 1024 * 1024
|
||||
DefaultDirPermissions = 0755
|
||||
AuditFlushInterval = 5 * time.Second
|
||||
)
|
||||
```
|
||||
|
||||
### 3.2 变量命名
|
||||
使用小驼峰命名法:
|
||||
|
||||
```go
|
||||
var (
|
||||
globalService *FileSystemService
|
||||
defaultConfig *Config
|
||||
defaultPermissions os.FileMode = 0644
|
||||
)
|
||||
```
|
||||
|
||||
### 3.3 接口命名
|
||||
接口名应该是动作或能力的描述,通常以 -er 结尾:
|
||||
|
||||
```go
|
||||
type Reader interface {
|
||||
Read(p []byte) (n int, err error)
|
||||
}
|
||||
|
||||
type Validator interface {
|
||||
Validate(path string) error
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 函数设计规范
|
||||
|
||||
### 4.1 函数长度
|
||||
推荐单个函数不超过50行。如果超过,考虑拆分子函数:
|
||||
|
||||
```go
|
||||
// 推荐:拆分子函数
|
||||
func DeletePath(path string) error {
|
||||
if err := validatePath(path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := checkPermissions(path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return performDelete(path)
|
||||
}
|
||||
|
||||
// 避免:长函数
|
||||
func DeletePath(path string) error {
|
||||
// 100行代码...
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 参数数量
|
||||
函数参数不超过5个。如果超过,使用结构体:
|
||||
|
||||
```go
|
||||
// 推荐:使用结构体
|
||||
type DeleteOptions struct {
|
||||
Path string
|
||||
Force bool
|
||||
SkipRecycle bool
|
||||
IgnoreLock bool
|
||||
Reason string
|
||||
}
|
||||
|
||||
func DeleteWithOptions(opts DeleteOptions) error {
|
||||
// 实现...
|
||||
}
|
||||
|
||||
// 避免:过多参数
|
||||
func DeleteWithOptions(path string, force bool, skipRecycle bool, ignoreLock bool, reason string, timeout int) error {
|
||||
// 参数过多
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 返回值
|
||||
函数返回值遵循以下顺序:
|
||||
1. 结果
|
||||
2. 错误
|
||||
|
||||
```go
|
||||
// 推荐
|
||||
func ReadFile(path string) ([]byte, error)
|
||||
|
||||
// 避免多个返回值
|
||||
func ReadFile(path string) ([]byte, bool, error, int)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 代码组织
|
||||
|
||||
### 5.1 文件组织
|
||||
每个文件应该有单一的职责:
|
||||
|
||||
```
|
||||
filesystem/
|
||||
├── fs.go # 核心文件操作
|
||||
├── service.go # 文件系统服务
|
||||
├── path_validator.go # 路径验证
|
||||
├── filetype_manager.go # 文件类型管理
|
||||
├── zip.go # ZIP操作
|
||||
├── errors.go # 错误定义
|
||||
├── logger.go # 日志记录
|
||||
└── constants.go # 常量定义
|
||||
```
|
||||
|
||||
### 5.2 导入顺序
|
||||
标准库 → 第三方库 → 项目内部:
|
||||
|
||||
```go
|
||||
import (
|
||||
// 标准库
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
// 第三方库
|
||||
"github.com/google/uuid"
|
||||
|
||||
// 项目内部
|
||||
"go-desk/internal/common"
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 性能规范
|
||||
|
||||
### 6.1 避免重复计算
|
||||
使用缓存或预计算:
|
||||
|
||||
```go
|
||||
// 推荐:缓存结果
|
||||
type statsCache struct {
|
||||
mu sync.RWMutex
|
||||
cache map[string]*DirectoryStats
|
||||
}
|
||||
|
||||
func (c *statsCache) Get(path string) (*DirectoryStats, error) {
|
||||
c.mu.RLock()
|
||||
if stats, ok := c.cache[path]; ok {
|
||||
c.mu.RUnlock()
|
||||
return stats, nil
|
||||
}
|
||||
c.mu.RUnlock()
|
||||
|
||||
// 计算并缓存
|
||||
stats, err := GetDirectoryStats(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.mu.Lock()
|
||||
c.cache[path] = stats
|
||||
c.mu.Unlock()
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// 避免:重复计算
|
||||
func processData(path string) {
|
||||
stats1, _ := GetDirectoryStats(path)
|
||||
stats2, _ := GetDirectoryStats(path) // 重复计算
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 资源释放
|
||||
使用 defer 确保资源释放:
|
||||
|
||||
```go
|
||||
// 推荐
|
||||
func ReadFile(path string) ([]byte, error) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close() // 确保关闭
|
||||
|
||||
return io.ReadAll(file)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 并发安全
|
||||
|
||||
### 7.1 共享状态
|
||||
使用互斥锁保护共享状态:
|
||||
|
||||
```go
|
||||
type SafeCounter struct {
|
||||
mu sync.RWMutex
|
||||
count int
|
||||
}
|
||||
|
||||
func (c *SafeCounter) Increment() {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
c.count++
|
||||
}
|
||||
|
||||
func (c *SafeCounter) Get() int {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
return c.count
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 避免数据竞争
|
||||
不要在goroutine中直接共享变量:
|
||||
|
||||
```go
|
||||
// 推荐:传递参数
|
||||
for i := 0; i < 10; i++ {
|
||||
go func(n int) {
|
||||
fmt.Println(n)
|
||||
}(i)
|
||||
}
|
||||
|
||||
// 避免:闭包捕获
|
||||
for i := 0; i < 10; i++ {
|
||||
go func() {
|
||||
fmt.Println(i) // 数据竞争
|
||||
}()
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 测试规范
|
||||
|
||||
### 8.1 测试文件命名
|
||||
测试文件命名为 `xxx_test.go`:
|
||||
|
||||
```go
|
||||
// fs_test.go
|
||||
package filesystem
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestDeletePath(t *testing.T) {
|
||||
// 测试代码
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 表格驱动测试
|
||||
使用表格驱动测试多种场景:
|
||||
|
||||
```go
|
||||
func TestValidatePath(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
path string
|
||||
wantErr bool
|
||||
}{
|
||||
{"正常路径", "/tmp/test.txt", false},
|
||||
{"路径遍历", "/tmp/../etc/passwd", true},
|
||||
{"空路径", "", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := ValidatePath(tt.path)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ValidatePath() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 文档规范
|
||||
|
||||
### 9.1 README
|
||||
每个模块应该有README说明:
|
||||
|
||||
```markdown
|
||||
# 文件系统模块
|
||||
|
||||
## 功能
|
||||
- 文件读写
|
||||
- 路径验证
|
||||
- ZIP操作
|
||||
|
||||
## 使用示例
|
||||
...
|
||||
|
||||
## 配置
|
||||
...
|
||||
```
|
||||
|
||||
### 9.2 API文档
|
||||
导出的函数和类型必须有文档注释。
|
||||
|
||||
---
|
||||
|
||||
## 10. 代码审查清单
|
||||
|
||||
提交代码前,确保:
|
||||
|
||||
- [ ] 移除所有emoji注释
|
||||
- [ ] 函数有文档注释
|
||||
- [ ] 错误处理完善(无忽略错误)
|
||||
- [ ] 命名符合规范
|
||||
- [ ] 无魔法数字(使用常量)
|
||||
- [ ] 无重复代码(遵循DRY)
|
||||
- [ ] 导入顺序正确
|
||||
- [ ] 资源正确释放(defer)
|
||||
|
||||
---
|
||||
|
||||
*版本: 1.0*
|
||||
*最后更新: 2026-01-27*
|
||||
Reference in New Issue
Block a user