580 lines
18 KiB
Go
580 lines
18 KiB
Go
/*
|
||
02-importing-packages.go - Go 语言包导入详解
|
||
|
||
学习目标:
|
||
1. 掌握包的导入语法和方式
|
||
2. 了解不同的导入模式
|
||
3. 学会处理包的别名和冲突
|
||
4. 理解包的初始化顺序
|
||
5. 掌握包导入的最佳实践
|
||
|
||
知识点:
|
||
- 包的导入语法
|
||
- 导入别名和点导入
|
||
- 空白导入
|
||
- 包的初始化顺序
|
||
- 循环导入问题
|
||
- 包管理工具的使用
|
||
*/
|
||
|
||
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"os"
|
||
"path/filepath"
|
||
"strings"
|
||
"time"
|
||
|
||
// 标准库导入
|
||
"encoding/json"
|
||
"io/ioutil"
|
||
|
||
// 本地包导入
|
||
"./utils" // 相对路径导入(不推荐)
|
||
|
||
// 别名导入
|
||
myutils "./utils"
|
||
|
||
// 点导入(不推荐)
|
||
. "fmt"
|
||
|
||
// 空白导入
|
||
_ "net/http/pprof"
|
||
)
|
||
|
||
func main() {
|
||
Println("=== Go 语言包导入详解 ===\n") // 使用点导入的 fmt.Println
|
||
|
||
// 演示基本导入
|
||
demonstrateBasicImports()
|
||
|
||
// 演示导入别名
|
||
demonstrateImportAliases()
|
||
|
||
// 演示点导入
|
||
demonstrateDotImports()
|
||
|
||
// 演示空白导入
|
||
demonstrateBlankImports()
|
||
|
||
// 演示包的初始化顺序
|
||
demonstrateInitializationOrder()
|
||
|
||
// 演示循环导入问题
|
||
demonstrateCircularImports()
|
||
|
||
// 演示包管理
|
||
demonstratePackageManagement()
|
||
}
|
||
|
||
// demonstrateBasicImports 演示基本导入
|
||
func demonstrateBasicImports() {
|
||
fmt.Println("1. 基本导入:")
|
||
|
||
// 导入语法
|
||
fmt.Printf(" 导入语法:\n")
|
||
fmt.Printf(" import \"package-path\" // 单个导入\n")
|
||
fmt.Printf(" import ( // 多个导入\n")
|
||
fmt.Printf(" \"fmt\"\n")
|
||
fmt.Printf(" \"time\"\n")
|
||
fmt.Printf(" \"strings\"\n")
|
||
fmt.Printf(" )\n")
|
||
|
||
// 标准库导入示例
|
||
fmt.Printf(" 标准库导入示例:\n")
|
||
|
||
// 使用 time 包
|
||
now := time.Now()
|
||
fmt.Printf(" 当前时间: %s\n", now.Format("2006-01-02 15:04:05"))
|
||
|
||
// 使用 strings 包
|
||
text := "Hello, World!"
|
||
upper := strings.ToUpper(text)
|
||
fmt.Printf(" 大写转换: %s -> %s\n", text, upper)
|
||
|
||
// 使用 json 包
|
||
data := map[string]interface{}{
|
||
"name": "Alice",
|
||
"age": 30,
|
||
"city": "Beijing",
|
||
}
|
||
|
||
jsonData, err := json.Marshal(data)
|
||
if err != nil {
|
||
fmt.Printf(" JSON 编码失败: %v\n", err)
|
||
} else {
|
||
fmt.Printf(" JSON 编码: %s\n", string(jsonData))
|
||
}
|
||
|
||
// 本地包导入示例
|
||
fmt.Printf(" 本地包导入示例:\n")
|
||
|
||
// 使用 utils 包
|
||
sum := utils.Add(10, 20)
|
||
fmt.Printf(" utils.Add(10, 20) = %d\n", sum)
|
||
|
||
product := utils.Multiply(5, 6)
|
||
fmt.Printf(" utils.Multiply(5, 6) = %d\n", product)
|
||
|
||
greeting := utils.GetGreeting("Go Developer")
|
||
fmt.Printf(" utils.GetGreeting(\"Go Developer\") = %s\n", greeting)
|
||
|
||
// 包的版本信息
|
||
fmt.Printf(" utils 包版本: %s\n", utils.PackageVersion)
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// demonstrateImportAliases 演示导入别名
|
||
func demonstrateImportAliases() {
|
||
fmt.Println("2. 导入别名:")
|
||
|
||
// 别名导入的用途
|
||
fmt.Printf(" 别名导入的用途:\n")
|
||
fmt.Printf(" 1. 解决包名冲突\n")
|
||
fmt.Printf(" 2. 简化长包名\n")
|
||
fmt.Printf(" 3. 提高代码可读性\n")
|
||
fmt.Printf(" 4. 避免与本地标识符冲突\n")
|
||
|
||
// 别名导入语法
|
||
fmt.Printf(" 别名导入语法:\n")
|
||
fmt.Printf(" import alias \"package-path\"\n")
|
||
fmt.Printf(" import (\n")
|
||
fmt.Printf(" myutils \"./utils\"\n")
|
||
fmt.Printf(" httputil \"net/http/httputil\"\n")
|
||
fmt.Printf(" )\n")
|
||
|
||
// 使用别名导入的包
|
||
fmt.Printf(" 使用别名导入的包:\n")
|
||
|
||
// 使用 myutils 别名
|
||
result := myutils.Add(15, 25)
|
||
fmt.Printf(" myutils.Add(15, 25) = %d\n", result)
|
||
|
||
maxVal := myutils.Max(10, 20)
|
||
fmt.Printf(" myutils.Max(10, 20) = %d\n", maxVal)
|
||
|
||
isEven := myutils.IsEven(42)
|
||
fmt.Printf(" myutils.IsEven(42) = %t\n", isEven)
|
||
|
||
// 常见的别名使用场景
|
||
fmt.Printf(" 常见的别名使用场景:\n")
|
||
|
||
// 场景1:解决包名冲突
|
||
fmt.Printf(" 场景1 - 解决包名冲突:\n")
|
||
fmt.Printf(" import (\n")
|
||
fmt.Printf(" \"crypto/rand\"\n")
|
||
fmt.Printf(" mathrand \"math/rand\"\n")
|
||
fmt.Printf(" )\n")
|
||
fmt.Printf(" // 使用: rand.Read() 和 mathrand.Intn()\n")
|
||
|
||
// 场景2:简化长包名
|
||
fmt.Printf(" 场景2 - 简化长包名:\n")
|
||
fmt.Printf(" import pb \"github.com/company/project/proto/user/v1\"\n")
|
||
fmt.Printf(" // 使用: pb.User{} 而不是 user_v1.User{}\n")
|
||
|
||
// 场景3:版本管理
|
||
fmt.Printf(" 场景3 - 版本管理:\n")
|
||
fmt.Printf(" import (\n")
|
||
fmt.Printf(" v1 \"myproject/api/v1\"\n")
|
||
fmt.Printf(" v2 \"myproject/api/v2\"\n")
|
||
fmt.Printf(" )\n")
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// demonstrateDotImports 演示点导入
|
||
func demonstrateDotImports() {
|
||
fmt.Println("3. 点导入:")
|
||
|
||
// 点导入的概念
|
||
fmt.Printf(" 点导入的概念:\n")
|
||
fmt.Printf(" - 使用 . 作为包别名\n")
|
||
fmt.Printf(" - 导入包的导出标识符到当前包的命名空间\n")
|
||
fmt.Printf(" - 可以直接使用导入包的函数,无需包名前缀\n")
|
||
fmt.Printf(" - 一般不推荐使用,容易造成命名冲突\n")
|
||
|
||
// 点导入语法
|
||
fmt.Printf(" 点导入语法:\n")
|
||
fmt.Printf(" import . \"fmt\"\n")
|
||
fmt.Printf(" import . \"math\"\n")
|
||
fmt.Printf(" // 使用: Println() 而不是 fmt.Println()\n")
|
||
|
||
// 点导入示例
|
||
fmt.Printf(" 点导入示例:\n")
|
||
|
||
// 直接使用 fmt 包的函数(通过点导入)
|
||
Printf(" 使用点导入的 Printf 函数\n")
|
||
Sprintf("格式化字符串") // 这里不会输出,只是演示语法
|
||
|
||
// 点导入的问题
|
||
fmt.Printf(" 点导入的问题:\n")
|
||
fmt.Printf(" 1. 命名冲突:可能与本地标识符冲突\n")
|
||
fmt.Printf(" 2. 可读性差:不清楚函数来自哪个包\n")
|
||
fmt.Printf(" 3. 维护困难:重构时难以追踪依赖\n")
|
||
fmt.Printf(" 4. 测试复杂:难以进行包级别的测试\n")
|
||
|
||
// 点导入的适用场景
|
||
fmt.Printf(" 点导入的适用场景:\n")
|
||
fmt.Printf(" 1. 测试文件:import . \"testing\"\n")
|
||
fmt.Printf(" 2. DSL 实现:领域特定语言\n")
|
||
fmt.Printf(" 3. 数学计算:import . \"math\"\n")
|
||
fmt.Printf(" 4. 临时脚本:快速原型开发\n")
|
||
|
||
// 替代方案
|
||
fmt.Printf(" 替代方案:\n")
|
||
fmt.Printf(" 1. 使用短别名:import f \"fmt\"\n")
|
||
fmt.Printf(" 2. 局部变量:var printf = fmt.Printf\n")
|
||
fmt.Printf(" 3. 包装函数:func print(args ...interface{}) { fmt.Print(args...) }\n")
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// demonstrateBlankImports 演示空白导入
|
||
func demonstrateBlankImports() {
|
||
fmt.Println("4. 空白导入:")
|
||
|
||
// 空白导入的概念
|
||
fmt.Printf(" 空白导入的概念:\n")
|
||
fmt.Printf(" - 使用 _ 作为包别名\n")
|
||
fmt.Printf(" - 只执行包的初始化,不使用包的导出标识符\n")
|
||
fmt.Printf(" - 主要用于触发包的副作用\n")
|
||
fmt.Printf(" - 避免编译器的未使用导入错误\n")
|
||
|
||
// 空白导入语法
|
||
fmt.Printf(" 空白导入语法:\n")
|
||
fmt.Printf(" import _ \"package-path\"\n")
|
||
fmt.Printf(" import (\n")
|
||
fmt.Printf(" _ \"net/http/pprof\" // 注册 pprof 处理器\n")
|
||
fmt.Printf(" _ \"image/jpeg\" // 注册 JPEG 解码器\n")
|
||
fmt.Printf(" )\n")
|
||
|
||
// 空白导入的用途
|
||
fmt.Printf(" 空白导入的用途:\n")
|
||
fmt.Printf(" 1. 数据库驱动注册\n")
|
||
fmt.Printf(" 2. 图像格式支持\n")
|
||
fmt.Printf(" 3. 插件系统\n")
|
||
fmt.Printf(" 4. 性能分析工具\n")
|
||
fmt.Printf(" 5. 静态资源嵌入\n")
|
||
|
||
// 常见的空白导入示例
|
||
fmt.Printf(" 常见的空白导入示例:\n")
|
||
|
||
// 1. 数据库驱动
|
||
fmt.Printf(" 1. 数据库驱动:\n")
|
||
fmt.Printf(" import (\n")
|
||
fmt.Printf(" \"database/sql\"\n")
|
||
fmt.Printf(" _ \"github.com/go-sql-driver/mysql\" // MySQL 驱动\n")
|
||
fmt.Printf(" _ \"github.com/lib/pq\" // PostgreSQL 驱动\n")
|
||
fmt.Printf(" )\n")
|
||
|
||
// 2. 图像格式支持
|
||
fmt.Printf(" 2. 图像格式支持:\n")
|
||
fmt.Printf(" import (\n")
|
||
fmt.Printf(" \"image\"\n")
|
||
fmt.Printf(" _ \"image/jpeg\" // JPEG 支持\n")
|
||
fmt.Printf(" _ \"image/png\" // PNG 支持\n")
|
||
fmt.Printf(" _ \"image/gif\" // GIF 支持\n")
|
||
fmt.Printf(" )\n")
|
||
|
||
// 3. HTTP 性能分析
|
||
fmt.Printf(" 3. HTTP 性能分析:\n")
|
||
fmt.Printf(" import _ \"net/http/pprof\"\n")
|
||
fmt.Printf(" // 自动注册 /debug/pprof/ 路由\n")
|
||
|
||
// 空白导入的注意事项
|
||
fmt.Printf(" 空白导入的注意事项:\n")
|
||
fmt.Printf(" 1. 增加编译时间和二进制大小\n")
|
||
fmt.Printf(" 2. 可能引入不需要的依赖\n")
|
||
fmt.Printf(" 3. 初始化顺序可能影响程序行为\n")
|
||
fmt.Printf(" 4. 难以追踪包的实际用途\n")
|
||
|
||
// 检查空白导入的效果
|
||
fmt.Printf(" 检查空白导入的效果:\n")
|
||
fmt.Printf(" net/http/pprof 包已通过空白导入加载\n")
|
||
fmt.Printf(" 可以通过 http://localhost:6060/debug/pprof/ 访问性能分析\n")
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// demonstrateInitializationOrder 演示包的初始化顺序
|
||
func demonstrateInitializationOrder() {
|
||
fmt.Println("5. 包的初始化顺序:")
|
||
|
||
// 初始化顺序规则
|
||
fmt.Printf(" 初始化顺序规则:\n")
|
||
fmt.Printf(" 1. 依赖包先初始化\n")
|
||
fmt.Printf(" 2. 同一包内按依赖关系初始化变量\n")
|
||
fmt.Printf(" 3. init 函数按文件名字典序执行\n")
|
||
fmt.Printf(" 4. 同一文件内 init 函数按出现顺序执行\n")
|
||
fmt.Printf(" 5. main 函数最后执行\n")
|
||
|
||
// 初始化示例
|
||
fmt.Printf(" 初始化示例:\n")
|
||
fmt.Printf(" 包 A 导入 包 B 和 包 C\n")
|
||
fmt.Printf(" 包 B 导入 包 D\n")
|
||
fmt.Printf(" 包 C 导入 包 D\n")
|
||
fmt.Printf("\\n")
|
||
fmt.Printf(" 初始化顺序: D -> B -> C -> A\n")
|
||
|
||
// 变量初始化顺序
|
||
fmt.Printf(" 变量初始化顺序:\n")
|
||
fmt.Printf(" var (\n")
|
||
fmt.Printf(" a = b + 1 // 第二个初始化\n")
|
||
fmt.Printf(" b = 2 // 第一个初始化\n")
|
||
fmt.Printf(" c = a + b // 第三个初始化\n")
|
||
fmt.Printf(" )\n")
|
||
|
||
// init 函数执行顺序
|
||
fmt.Printf(" init 函数执行顺序:\n")
|
||
fmt.Printf(" 文件 a.go:\n")
|
||
fmt.Printf(" func init() { fmt.Println(\"a.go init 1\") }\n")
|
||
fmt.Printf(" func init() { fmt.Println(\"a.go init 2\") }\n")
|
||
fmt.Printf("\\n")
|
||
fmt.Printf(" 文件 b.go:\n")
|
||
fmt.Printf(" func init() { fmt.Println(\"b.go init 1\") }\n")
|
||
fmt.Printf("\\n")
|
||
fmt.Printf(" 执行顺序: a.go init 1 -> a.go init 2 -> b.go init 1\n")
|
||
|
||
// 实际初始化演示
|
||
fmt.Printf(" 实际初始化演示:\n")
|
||
fmt.Printf(" utils 包的初始化信息:\n")
|
||
fmt.Printf(" 版本: %s\n", utils.Version)
|
||
fmt.Printf(" 最大重试次数: %d\n", utils.MaxRetries)
|
||
|
||
// 初始化最佳实践
|
||
fmt.Printf(" 初始化最佳实践:\n")
|
||
fmt.Printf(" 1. 保持 init 函数简单\n")
|
||
fmt.Printf(" 2. 避免复杂的初始化逻辑\n")
|
||
fmt.Printf(" 3. 不要依赖 init 函数的执行顺序\n")
|
||
fmt.Printf(" 4. 处理初始化可能的错误\n")
|
||
fmt.Printf(" 5. 使用延迟初始化处理复杂情况\n")
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// demonstrateCircularImports 演示循环导入问题
|
||
func demonstrateCircularImports() {
|
||
fmt.Println("6. 循环导入问题:")
|
||
|
||
// 循环导入的概念
|
||
fmt.Printf(" 循环导入的概念:\n")
|
||
fmt.Printf(" - 两个或多个包相互导入\n")
|
||
fmt.Printf(" - Go 编译器禁止循环导入\n")
|
||
fmt.Printf(" - 会导致编译错误\n")
|
||
fmt.Printf(" - 需要重新设计包结构来解决\n")
|
||
|
||
// 循环导入示例
|
||
fmt.Printf(" 循环导入示例:\n")
|
||
fmt.Printf(" 包 A:\n")
|
||
fmt.Printf(" package a\n")
|
||
fmt.Printf(" import \"myproject/b\"\n")
|
||
fmt.Printf(" func UseB() { b.FuncB() }\n")
|
||
fmt.Printf("\\n")
|
||
fmt.Printf(" 包 B:\n")
|
||
fmt.Printf(" package b\n")
|
||
fmt.Printf(" import \"myproject/a\" // 循环导入!\n")
|
||
fmt.Printf(" func UseA() { a.FuncA() }\n")
|
||
|
||
// 循环导入的检测
|
||
fmt.Printf(" 循环导入的检测:\n")
|
||
fmt.Printf(" 编译错误信息:\n")
|
||
fmt.Printf(" import cycle not allowed\n")
|
||
fmt.Printf(" package myproject/a\n")
|
||
fmt.Printf(" imports myproject/b\n")
|
||
fmt.Printf(" imports myproject/a\n")
|
||
|
||
// 解决循环导入的方法
|
||
fmt.Printf(" 解决循环导入的方法:\n")
|
||
fmt.Printf(" 1. 提取公共接口\n")
|
||
fmt.Printf(" 2. 创建中间包\n")
|
||
fmt.Printf(" 3. 重新组织包结构\n")
|
||
fmt.Printf(" 4. 使用依赖注入\n")
|
||
fmt.Printf(" 5. 合并相关包\n")
|
||
|
||
// 解决方案示例
|
||
fmt.Printf(" 解决方案示例:\n")
|
||
fmt.Printf(" 方案1 - 提取公共接口:\n")
|
||
fmt.Printf(" 包 interfaces:\n")
|
||
fmt.Printf(" type ServiceA interface { MethodA() }\n")
|
||
fmt.Printf(" type ServiceB interface { MethodB() }\n")
|
||
fmt.Printf("\\n")
|
||
fmt.Printf(" 包 A 导入 interfaces\n")
|
||
fmt.Printf(" 包 B 导入 interfaces\n")
|
||
fmt.Printf(" main 包导入 A 和 B,进行依赖注入\n")
|
||
|
||
fmt.Printf(" 方案2 - 创建中间包:\n")
|
||
fmt.Printf(" 包 common: 包含 A 和 B 都需要的功能\n")
|
||
fmt.Printf(" 包 A 导入 common\n")
|
||
fmt.Printf(" 包 B 导入 common\n")
|
||
fmt.Printf(" A 和 B 不再相互导入\n")
|
||
|
||
// 预防循环导入
|
||
fmt.Printf(" 预防循环导入:\n")
|
||
fmt.Printf(" 1. 设计清晰的包层次结构\n")
|
||
fmt.Printf(" 2. 遵循依赖倒置原则\n")
|
||
fmt.Printf(" 3. 使用接口定义包边界\n")
|
||
fmt.Printf(" 4. 定期检查包依赖关系\n")
|
||
fmt.Printf(" 5. 使用工具检测循环依赖\n")
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// demonstratePackageManagement 演示包管理
|
||
func demonstratePackageManagement() {
|
||
fmt.Println("7. 包管理:")
|
||
|
||
// Go Modules 概念
|
||
fmt.Printf(" Go Modules 概念:\n")
|
||
fmt.Printf(" - Go 1.11+ 的官方包管理工具\n")
|
||
fmt.Printf(" - 替代 GOPATH 模式\n")
|
||
fmt.Printf(" - 支持版本管理和依赖解析\n")
|
||
fmt.Printf(" - 使用 go.mod 文件定义模块\n")
|
||
|
||
// go.mod 文件示例
|
||
fmt.Printf(" go.mod 文件示例:\n")
|
||
fmt.Printf(" module myproject\n")
|
||
fmt.Printf("\\n")
|
||
fmt.Printf(" go 1.19\n")
|
||
fmt.Printf("\\n")
|
||
fmt.Printf(" require (\n")
|
||
fmt.Printf(" github.com/gin-gonic/gin v1.9.1\n")
|
||
fmt.Printf(" github.com/go-redis/redis/v8 v8.11.5\n")
|
||
fmt.Printf(" )\n")
|
||
fmt.Printf("\\n")
|
||
fmt.Printf(" replace github.com/old/package => github.com/new/package v1.0.0\n")
|
||
|
||
// 常用的 go mod 命令
|
||
fmt.Printf(" 常用的 go mod 命令:\n")
|
||
commands := map[string]string{
|
||
"go mod init <module>": "初始化新模块",
|
||
"go mod tidy": "添加缺失的依赖,移除未使用的依赖",
|
||
"go mod download": "下载依赖到本地缓存",
|
||
"go mod verify": "验证依赖的完整性",
|
||
"go mod graph": "打印模块依赖图",
|
||
"go mod why <package>": "解释为什么需要某个包",
|
||
"go mod edit": "编辑 go.mod 文件",
|
||
"go mod vendor": "将依赖复制到 vendor 目录",
|
||
}
|
||
|
||
for cmd, desc := range commands {
|
||
fmt.Printf(" %-25s - %s\n", cmd, desc)
|
||
}
|
||
|
||
// 版本管理
|
||
fmt.Printf(" 版本管理:\n")
|
||
fmt.Printf(" 语义化版本: v1.2.3\n")
|
||
fmt.Printf(" 主版本号: 不兼容的 API 变更\n")
|
||
fmt.Printf(" 次版本号: 向后兼容的功能增加\n")
|
||
fmt.Printf(" 修订版本号: 向后兼容的问题修复\n")
|
||
fmt.Printf("\\n")
|
||
fmt.Printf(" 版本约束:\n")
|
||
fmt.Printf(" v1.2.3 - 精确版本\n")
|
||
fmt.Printf(" v1.2 - 最新的 v1.2.x\n")
|
||
fmt.Printf(" v1 - 最新的 v1.x.x\n")
|
||
fmt.Printf(" latest - 最新版本\n")
|
||
|
||
// 私有包管理
|
||
fmt.Printf(" 私有包管理:\n")
|
||
fmt.Printf(" 环境变量设置:\n")
|
||
fmt.Printf(" GOPRIVATE=github.com/mycompany/*\n")
|
||
fmt.Printf(" GONOPROXY=github.com/mycompany/*\n")
|
||
fmt.Printf(" GONOSUMDB=github.com/mycompany/*\n")
|
||
|
||
// 检查当前项目的模块信息
|
||
fmt.Printf(" 当前项目信息:\n")
|
||
|
||
// 查找 go.mod 文件
|
||
currentDir, _ := os.Getwd()
|
||
goModPath := filepath.Join(currentDir, "go.mod")
|
||
|
||
if _, err := os.Stat(goModPath); err == nil {
|
||
content, err := ioutil.ReadFile(goModPath)
|
||
if err == nil {
|
||
fmt.Printf(" 找到 go.mod 文件:\n")
|
||
lines := strings.Split(string(content), "\n")
|
||
for i, line := range lines {
|
||
if i < 10 { // 只显示前10行
|
||
fmt.Printf(" %s\n", line)
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
fmt.Printf(" 当前目录没有 go.mod 文件\n")
|
||
fmt.Printf(" 可以使用 'go mod init <module-name>' 初始化\n")
|
||
}
|
||
|
||
// 包管理最佳实践
|
||
fmt.Printf(" 包管理最佳实践:\n")
|
||
fmt.Printf(" 1. 使用语义化版本号\n")
|
||
fmt.Printf(" 2. 定期更新依赖\n")
|
||
fmt.Printf(" 3. 锁定关键依赖的版本\n")
|
||
fmt.Printf(" 4. 使用 go mod tidy 清理依赖\n")
|
||
fmt.Printf(" 5. 提交 go.mod 和 go.sum 文件\n")
|
||
fmt.Printf(" 6. 避免使用 replace 指令在生产环境\n")
|
||
fmt.Printf(" 7. 定期检查安全漏洞\n")
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
/*
|
||
运行这个程序:
|
||
go run 02-importing-packages.go
|
||
|
||
学习要点:
|
||
1. Go 语言支持多种包导入方式
|
||
2. 包的导入路径决定了包的唯一性
|
||
3. 包的初始化有明确的顺序规则
|
||
4. 循环导入是被禁止的,需要重新设计包结构
|
||
5. Go Modules 是现代 Go 项目的标准包管理方式
|
||
|
||
包导入方式:
|
||
1. 基本导入:import "package-path"
|
||
2. 别名导入:import alias "package-path"
|
||
3. 点导入:import . "package-path"(不推荐)
|
||
4. 空白导入:import _ "package-path"
|
||
|
||
导入路径类型:
|
||
1. 标准库:fmt, time, strings 等
|
||
2. 相对路径:./utils, ../common(不推荐)
|
||
3. 绝对路径:github.com/user/project/pkg
|
||
4. 内部包:internal/ 目录下的包
|
||
|
||
包初始化顺序:
|
||
1. 依赖包先初始化
|
||
2. 包级别变量按依赖关系初始化
|
||
3. init 函数按文件名和出现顺序执行
|
||
4. main 函数最后执行
|
||
|
||
循环导入解决方案:
|
||
1. 提取公共接口
|
||
2. 创建中间包
|
||
3. 重新组织包结构
|
||
4. 使用依赖注入
|
||
5. 合并相关包
|
||
|
||
Go Modules 特性:
|
||
1. 版本管理:支持语义化版本
|
||
2. 依赖解析:自动解决依赖冲突
|
||
3. 模块缓存:提高构建速度
|
||
4. 安全验证:校验包的完整性
|
||
5. 私有包支持:支持私有仓库
|
||
|
||
最佳实践:
|
||
1. 使用 Go Modules 管理依赖
|
||
2. 遵循包导入的命名规范
|
||
3. 避免使用点导入和相对路径导入
|
||
4. 合理使用空白导入
|
||
5. 定期清理和更新依赖
|
||
6. 提交 go.mod 和 go.sum 文件
|
||
7. 使用工具检测循环依赖
|
||
|
||
注意事项:
|
||
1. 包的导入路径必须唯一
|
||
2. 同一目录下的文件必须属于同一包
|
||
3. 包名通常与目录名相同
|
||
4. 避免循环导入
|
||
5. 合理使用包的可见性规则
|
||
*/
|