go 包
包
go中最小分发单位
存放变量函数数据
每个包都可以作为独立的但愿维护并提供给其他项目进行使用
包的定义调用
定义:
main包:可运行
非main包:库文件
包名尽量小写,常与目录名保持一致
一个包中由多个go文件组成,每个go文件需要写入package 包名
文件组成:
bin:二进制程序发布目录 go install pkgpath -- > main包
pkg:库文件发布目录,go install pkgpath --> 非main包
src:源码目录,包目录
执行命令:
go build:构建编译,当前目录生成.exe文件,不会发布到bin目录
go install:发布程序到bin目录,并会生成.exe文件
go install -a:强制编译所有的库
build后的文件保存在GoPath的bin目录下中
go env:查看环境信息
go run: 运行二进制文件
go get github/tcy110!/project: 将项目下载到本地
包的作用:
- 包可以区分相同名字的函数以及变量等标识符
- 当程序庞大,将程序不同部分写在不一样的文件夹(包)中,方便对项目的管理
- 控制函数已经变量的访问范围,可以通过将其放置在不同的包来实现。
包的引入:
- import导入语句通常放在源码文件开头包声明语句的下面
- 导入包需要用双引号包裹起来
- 包名是从GOPAH/src/后开始计算的,使用/进行路径分隔
包变量:
- 如需包中变量被其他包能使用,那变量名首字母需要大写
// 在src目录下新建两个dir,为pkg & testpkg
// 目录中分别存放pkg/version.go & testpkg/main.go
// pkg/version.go
package pkg // 指定当前包名
const Version = 1.1
// testpkg/main.go
package main
import (
"fmt"
"pkg" // 导入和testpkg同级目录下的pkg包
localpkg "pkg" // 为pkg包设置别名
_ "pkg" // 导入包不使用,和初始化函数一起使用
. "pkg" // 点导入方式,后面直接可以用变量名,不用加包名,少用
)
func main() {
fmt.Println(pkg.Version) // 直接使用导入包中的常量
fmt.Pringln(localpkg.Version) // 使用别名导入
}
mian包与main函数
main包用于声明告知编译器将包编译为二进制可执行文件
在main包中的main函数是程序的入口,无返回值,无参数,一个包中只能有一个main函数
包类型:
可执行程序:main
库:其他包文件
init函数
init函数是初始化包使用,无返回值,无参数,建议每个包只定义一个,init函数在import包时被自动调用, 对包中数据初始化。import pkgname时被执行
func init() {}
(包const - > 包var - > init)
一个包中可以有多个初始化函数
gopath+vendor
当存在依赖,有使用别人相关库,为了避免相关库被删除,可以将包拷贝至当前项目的verdor目录下
这样就算被依赖的库删除,我的编译也依然能通过
顺序:当前执行文件下找vendor --> 上一级目录下找vendor --> GOPATH/src/vendor --> GOROOT
注意:
gomode和gopath只能二选一
当使用gopath,下载包需要使用go get
当使用gomodule,无需对包下载,直接go build会自动下载依赖
go get 参数
-d :仅下载依赖包
-u:更新包并安装
-x:打印执行的命令
-v 打印构建的包
-insecure:允许使用http下载
第三方包查找地址:
htts://godoc.org
go module
优势:
- 不用设置GOPATH,代码可以放置任意位置
- 自动下载依赖管理
- 版本控制
- 不允许使用相对导入
- replace机制
// 初始化,目录下会存在一个go.mod文件
go mod init gihub.com/tcy/testmod
// 将不被识别编译的包将手动添加,这样go build就不会报错
// replace可以将获取不到的包,通过另外的路径去获取,执行后会go.mod中添加相关指令
go mod edit -replace=golang.org/x/crypto=github.com/golang/cryptop@laster
// go.mod中的require
会将依赖的库写入
// 常用命令:
go mod tidy:整理依赖模块(添加新增的,删除未使用的)
go mod vendor:将依赖模块拷贝到模块中的vendor目录
go build:编译当前模块
go build ./...:编译当前目录下的所有模块
go build -mod=vendor:使用当前模块下的vendor目录中的包进行编译
go mod download:仅下载第三方模块
go mod grapha: 打印所有第三方模块
go list -m -json all: 显示所有模块信息
go mod edit:修改go.mod文件
-replace功能将包替换为本地包,实现相对导入
// go.sum文件
单元测试
对哪个功能需要测试,相当于新建一个go文件,写上功能测试函数。也叫测试用例
测试代码文件命名: _test.go
测试函数命名:Test开头
函数参数: *testing.T
函数的返回值:无
函数体:t.Error 或者 t.Errorf
go test 项目/包名:执行测试操作
go test 项目/包名 -converprofile-cover.out:获取覆盖测试率
go tool cover -html cover.out:图形界面查看测试覆盖率
基准测试
也就是性能测试
函数要求:
命名:Beachmark开头
参数:*testing.B
返回值:无
函数体:循环n次执行代码
命令行参数
// 代码,返回切片,一个参数为脚本路径
func main() {
fmt.Println(os.Args)
}
// 终端执行
go run args.go test aaa bbb ccc
// 输出:[C:\Users\CAIYU~1.TAN\AppData\Local\Temp\go-build2466932673\b001\exe\args.exe test aaa bbb ccc]
- 接收命令行参数(方式一)
// 函数代码
func main() {
var port int
var host string
var verbor bool
var help bool
// 绑定命令行参数与变量关系
flag.IntVar(&port, "p", 22, "ssh port")
flag.StringVar(&host, "H", "127.0.0.1", "ssh host")
flag.BoolVar(&verbor, "v", false, "detail log")
flag.Usage = func() {
fmt.Println("usage: flagargs [-H 127.0.0.1] [-p 22] [-v]")
flag.PrintDefaults() // 打印默认帮助信息
}
// 解析命令行参数
flag.Parse()
if help {
flag.Usage()
} else {
fmt.Println(port, host, verbor)
}
}
// 终端执行
PS F:\GoLand\Go-project\go1.18.1\src\stdpkg> go run flagargs.go -h
usage: flagargs [-H 127.0.0.1] [-p 22] [-v]
-H string
ssh host (default "127.0.0.1")
-p int
ssh port (default 22)
-v detail log
- 接收命令行参数(方式二)
func main() {
// 绑定命令行参数与变量关系
port := flag.Int("p", 22, "ssh port")
host := flag.String("H", "127.0.0.1", "ssh host")
verbos := flag.Bool("v", false, "detail log")
flag.Usage = func() {
fmt.Println("usage: flagargs [-H 127.0.0.1] [-p 22] [-v]")
flag.PrintDefaults()
}
// 解析命令行参数
flag.Parse()
fmt.Printf("%T %T %T", port, host, verbos) // *int *string *bool 获取指针类型
fmt.Printf("%v %v %v", *port, *host, *verbos) // 22 127.0.0.1 false
}
时间模块
func main() {
now := time.Now()
fmt.Printf("%T\n", now) // time.Time
fmt.Printf("%v\n", now) // 2022-05-01 11:32:12.8953429 +0800 CST m=+0.004311701
fmt.Println(time.Now())
time.Sleep(time.Second * 5) // 让程序休眠5秒
fmt.Println(time.Now())
t := now.Add(3 * time.Hour) // 计算当前时间往后3个小时的时间
fmt.Println(t)
// 时间转换 now.Format
}
hash算法
- md5计算的两种方式:
func main() {
bytes := md5.Sum([]byte("i'amkk")) // 计算md5
x := fmt.Sprintf("%x", bytes)
fmt.Println(x) // 转换为16进制
fmt.Println(bytes) // [206 194 148 58 249 235 181 164 226 103 56 121 60 143 13 114]
fmt.Println(hex.EncodeToString(bytes[:])) // 转换为16进制
m := md5.New() // 当需要计算的md5过大,可以拆解
m.Write([]byte("i'am"))
m.Write([]byte("kk"))
fmt.Printf("%x\n", m.Sum(nil)) // cec2943af9ebb5a4e26738793c8f0d72
}
- base64编码解码
// base64
// 将字节数组转换为base64类型的字符串
x := base64.StdEncoding.EncodeToString([]byte("I'am kk"))
fmt.Println(x) // SSdhbSBraw==
bytes, err := base64.StdEncoding.DecodeString(x) // 解码
fmt.Println(string(bytes), err) // 解码结果转换为字符串
日志
func main() {
log.Printf("我是print日志: %s", "x") // 2022/05/01 14:57:18 我是print日志: x
log.SetPrefix("prefix:") // 后续的日志打印都会加上前缀
// Falgs(获取当前日志标签) & SetFlags(设置)
//log.SetFlags(log.Flags() | log.Lshortfile) // 后续打印日志加上文件名
log.SetFlags(log.Flags() | log.Llongfile) // 后续答应日志加上日志路径
//log.Panic("我是Panic日志:%s", "y") // 不常用
log.Fatalf("我是Fatalf日志:%s", "z") // 和printf结果一样,不过会退出
}
隐藏密码
import (
"fmt"
"github.com/howeyc/gopass"
)
func main() {
fmt.Print("请输入密码:")
bytes, _ := gopass.GetPasswd()
fmt.Println(string(bytes))
}