GVM 脚手架探险记02:那些让我拍大腿的Go技巧彩蛋
正确的快速的初始化环境
打开 GVM 项目的 main.go 文件,首先就是可以看到如下代码注释
//go:generate go env -w GO111MODULE=on
//go:generate go env -w GOPROXY=https://goproxy.cn,direct
//go:generate go mod tidy
//go:generate go mod download
这些是 Go 语言的 //go:generate 指令,它们用于在构建前自动执行一些准备工作。
//go:generate go env -w GO111MODULE=on
作用:设置 Go 模块模式为开启状态
详细解释:GO111MODULE 是 Go 1.11 引入的环境变量,控制模块支持。设置为 on 表示强制启用 Go 模块模式。-w 表示将设置写入环境变量(持久化)。
//go:generate go env -w GOPROXY=https://goproxy.cn,direct
作用:设置 Go 模块代理
详细解释:GOPROXY 指定从哪里下载 Go 模块。https://goproxy.cn 是中国的一个 Go 模块镜像,可以加速国内下载。direct 表示如果代理找不到,直接从版本控制系统(如 GitHub)下载。多个地址用逗号分隔,会按顺序尝试。
//go:generate go mod tidy
作用:整理和同步模块依赖
详细解释:添加项目需要的但缺失的依赖。移除项目不再使用的依赖。更新 go.mod 和 go.sum 文件。
//go:generate go mod download
作用:下载模块依赖到本地缓存
详细解释:下载 go.mod 文件中指定的所有依赖。下载的模块会存储在 $GOPATH/pkg/mod 目录下。
指令执行方式: go generate
扩展的时间解析方法
GVM 脚手架中使用了自定义的时间解析方法,支持解析包含天的时长字符串,
如 “3d”、“2d6h30m”。
go
// utils/human_duration.go
package utils
import (
"strconv"
"strings"
"time"
)
// ParseDuration 自定义的解析时间的方法
// 支持解析包含天的时长字符串,如 "3d"、"2d6h30m"
func ParseDuration(d string) (time.Duration, error) {
// 去除字符串首尾空格
d = strings.TrimSpace(d)
// 尝试用标准库解析
dr, err := time.ParseDuration(d)
if err == nil {
return dr, nil
}
// 当字符串包含 "d" 时,将其视为天单位
if strings.Contains(d, "d") {
index := strings.Index(d, "d")
hour, _ := strconv.Atoi(d[:index])
dr = time.Hour * 24 * time.Duration(hour)
ndr, err := time.ParseDuration(d[index+1:])
if err != nil {
return dr, nil
}
return dr + ndr, nil
}
// 尝试将输入解析为整数
dv, err := strconv.ParseInt(d, 10, 64)
// 直接转换为 time.Duration 类型(单位为纳秒)
return time.Duration(dv), err
}
类型说明
time.Duration → 用于表示 时间间隔(如 5s、2h),适合计算时间差、延时等。
time.Time → 用于表示 具体时间点(如 2023-10-01 12:00:00),适合存储和操作日期时间。
time.Time → 用于表示 具体时间点(如 2023-10-01 12:00:00),适合存储和操作日期时间。
利用 mod 配置文件配置模块名
可以参考读取配置文件的思想来做一些配置默认值。
go
// initialize/other.go
// 尝试打开当前目录下的 go.mod 文件
file, err := os.Open("go.mod")
if err == nil && global.GVA_CONFIG.AutoCode.Module == "" {
defer file.Close() // 确保文件被关闭
// bufio.NewScanner(file) 创建一个 Scanner 文件扫描器,用于逐行读取文件内容
scanner := bufio.NewScanner(file)
// scanner.Scan() 读取文件的下一行(这里只读取第一行)。
scanner.Scan()
// scanner.Text() 返回当前行的内容
global.GVA_CONFIG.AutoCode.Module = strings.TrimPrefix(scanner.Text(), "module ")
}