包
包 == package 为什么要用包?
- 更好的管理项目模块、功能
- 实现同名方法、变量等
- 控制访问范围(又称
作用域
) - 总结: 就是更好的分功能、分模块的管理代码
Go Module依赖管理
go mod init [模块名称]
- 同一个目录下的代码 package 声明一样不需要引入
- 引入第三方包 go get 包地址
- 没有使用的可以用
_
重命名- 也会执行对应包里面的init函数
- 包的init函数可以是多个
- 引入包会默认的依次执行 init 函数
- 目录结构
// => 项目 g6
|- main.go
|- util
| - a.go (package utils)
| - b.go (package utils)
| - math
| - math.go (package maths)
- main.go
- go get github.com/bytedance/sonic
package main
import (
"fmt"
"g6/util"
math "g6/util/main" //别名
"bytedance/sonic"
)
func main() {
fmt.Println(util.Name)
fmt.Println(util.Add(1, 2, 3))
fmt.Println(math.Add(1, 2))//没有别名的化 maths.Add()
}
go mod tidy
- 当发现代码里面引入了第三方包的时候,自动下载引入第三方包(go.mod)
包函数的使用
- 非本package(包)中的函数
- 导入使用的包
- import ""
- package name = + 目录
- 调包里面的函数
- <函数名称> -> 直接用就完事了
- 导入使用的包
package main
import (
"fmt"
utils "ls/utils"//起别名
)
func main() {}
包引入
github.com/spf13/cobra
go mod tidy
拉包
package main
import (
"fmt"
// "os"
"github.com/spf13/cobra"
// _ "github.com/spf13/cobra" //用来转类型的
// go mod tidy
)
// 让我们的体脂计算器接收传入的姓名、性别、身高、体重来计算体脂率
func main() {
var (
name string
gender string
// tail string // float64
// weight string //float64
// age string //int
tail float64
weight float64
age int
)
// arguments := os.Args
// name = arguments[1]
// gender = arguments[2]
// tail = arguments[3]
// weight = arguments[4]
// age = arguments[5]
cmd := &cobra.Command{
Use: "health", //命令行的名字
Short: "体脂计算器、根据身高、体重、性别、年龄计算", //短描述
Long: "该体脂率计算基于BMI的体脂计算...", //长描述
Run: func(cmd *cobra.Command, args []string) {
// 计算
// bmi := calculator.CalcBMI(tail, weight)
// fatRate := calculator.CalcFatRate(bmi, age, gender)
// 评估结果
// 别的包区实现
},
}
cmd.Flags().StringVar(&name, "name", "", "姓名")
cmd.Flags().StringVar(&gender, "gender", "", "性别")
cmd.Flags().Float64Var(&tail, "tail", 0, "身高")
cmd.Flags().Float64Var(&weight, "weight", 0, "体重")
cmd.Flags().IntVar(&age, "age", 0, "年龄")
fmt.Println(name, gender, tail, weight, age)
// go run . 小白 男 1.7 60 29
cmd.ExecuteC()
}
/*
go run main.go -help
health [flags]
Flags:
--age int 年龄
--gender string 性别
-h, --help help for health
--name string 姓名
--tail float 身高
--weight float 体重
自定义顺序
go run main.go --age 18 --name 江小北 --weight 65 --tail 1.7 --gender 男
*/
go.mod
: 做包管理的的文件go.sum
: 隐藏的依赖
go module进阶
- 编写代码时,会遇到找不到 package、func的错误,运行
- go get -> 指定的包
- go mod tidy
- 像正常代码使用
- go.mod 文件务必在 打开文件夹的位置
- 运行 go mod tidy 来保证项目中使用到的 go modules被包含在项目依赖中
Go Module 替换
- Go Module 替换(replace) 是用另一个实现替换默认要使用的实现
- 默认 tidy 出来的版本是最新版本,有时候是不合适的,则需要替换为相对旧的版本
- 我们提供定制的版本,并开源在git服务上,需要将 module重定向
- 本地有些项目的代码,需要作为独立的 module 使用
- go.mod
replace (
//包
地址 版本号(v0.0.0)
)
思考
- Go Module 管理依赖已经很完善了,是不是使用了Go Module 就万无一失了?
- 不是万无一失的 1.1 Go Module 完全依赖git服务,与git上的branch、release tag 相关。 1.2 Git 服务不属于 Go Module 的管理范围 1.3 Git 上的branch、release 可以随时被删除、重写
- 对项目的影响 2.1 项目可能因为 git 服务的变更无法编译 2.2 编译出来的程序行为不一致
Vendor 简介
- vendor 是把项目 module 定义的所有依赖制作一个副本保存在项目的vendor 目录
- 就是将项目定义的依赖做一个快照并保存下来,避免项目依赖的变更影响项目的一致性
- Go module 深度支持 vendor, 通过命令 go mod vendor 将项目依赖保存在 vendor中
- 会产生一个 vendor 文件夹
Go module 与 vendor共存
- Go build/run 通过命令行选项来控制 -mod=<vendor|mod|readonly>
- vendor: 使用vendor中的依赖来编译项目
- mod: 使用go module 定义的依赖编译项目, 并且会自动更新 go.mod 定义
- readonly: 使用 go module定义的依赖编译项目,并且不做任何依赖的升级
注意
- 项目中如果有vendor目录,Go在编译时默认使用vendor提供的依赖
- 如果没有 vendor目录,Go在编译时默认使用readonly
目录
- 整洁代码的价值
- 更容易看懂
- 更容易修改
- 更容易测试
- 更容易上线
- 方法、函数内部
- 通常100 行左右的方法会比较容易理解
- 怎么避免冗余代码
- 将代码拆分为多个子方法
- 提出特定的对象,将各个方法转换为特定对象的方法
- 主逻辑清晰
- 复杂逻辑的嵌套: 多个 if-else、for、switch的控制代码
- 嵌套内部的逻辑拆分为子方法
- 目的单一
- 方法的目的要单一: 一次只做一件事情。事情可大可小
- 方法、函数之间
- 起一个好名字: 见名知意
- 避免太多的方法参数、返回值
- 一致的方法抽象
- 读写分离