430 lines
7.4 KiB
Markdown
430 lines
7.4 KiB
Markdown
# 文件管理模块代码风格规范
|
||
|
||
## 概述
|
||
|
||
本文档定义了文件管理模块的代码风格规范,确保代码一致性、可读性和可维护性。
|
||
|
||
---
|
||
|
||
## 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*
|