Golang学习笔记(1):包管理
Golang学习笔记(1):包管理
本人学习Golang主要是为了做MIT6.824的lab,然而一上来就被Golang神奇的import搞混了,因此写一篇博客记录学习Golang的包管理的过程。
package main
import "fmt"
func main() {
fmt.Println("hello, world")
}
如果有编程基础肯定会觉得这段代码很好理解,它可以在终端输入hello,world并自动换行。但如果深究这段代码里的细节我们可以提出很多有价值的问题。
package main
是什么意思?fmt
也是一个package
吗?- 如果把
func
作为main
函数的关键词提示,那么它返回什么,传入什么?这在Golang里该如何表示?
本篇文章主要解决关于package
的问题,因为这个问题在根本上和博主熟知的C语言不一样,他们的区别绝对不是include
和 import
不同写法的区别。
首先展示一下我把import
当include
用遇到的问题
文件目录:
.
├── main.go
└── pkg_va.go
1 directory, 2 files
main.go
package main
import (
"fmt"
"mypkg"
)
func main() {
fmt.Println(mypkg.I)
}
pkg_var.go
package mypkg
var I int
func init() {
I = 10
}
按我的想法我把mypkg
包括进来了就应该能用mypkg相关文件
里的值了。
然而却遇到了这样的问题
xiongzile@LAPTOP-S6FR5EAE:~/workspace/demo/go$ go run main.go
main.go:5:2: package mypkg is not in std (/usr/lib/go-1.22/src/mypkg)
这段报错说是系统中找不到我的包,如果你对C语言很熟悉你就会想到这是
#include <xxx.h>
而这个xx.h是你自己定义的头文件会出现的错误。
那我们有没有类似
#include "xxx.h"
的表达呢?
很遗憾Golang似乎是没有的,发现了这一点我就明白了学C的我对包管理还是一窍不通的状态,所以我要开始学习Golang的包管理了!
早期Golang的包管理很简单粗暴, 有一个GOPATH
环境变量, 系统识别包路径不仅会识别std里的,还会识别这个环境变量对应的路径下的。 这会导致开发者创建项目是不自由的,随时要改GOPATH
环境变量,我认为没人想每次换路径都改环境变量。
Golang认识到这一点之后推出了Modules包管理,也就是现在的Go开发者真正需要学习了解的,也是这篇博客的重点。
回到刚才那个问题,我们如何用Go Modules来管理外部库(我们自己写的库或者在网上找的别人写的库)的依赖?
首先要在项目根目录下启动我们自己的Go模块:
go mod init yourmodulename
效果如下:
xiongzile@LAPTOP-S6FR5EAE:~/workspace/demo/go$ go mod init mymod
go: creating new go.mod: module mymod
go: to add module requirements and sums:
go mod tidy
这样我们就有了一个自己的模板,我们可以在这里自由的导入或者移除外部库
修改一下main.go代码
package main
import (
"fmt"
"mymod/mypkg"
)
func main() {
fmt.Println(mypkg.I)
}
这样是不是就可以了呢?
xiongzile@LAPTOP-S6FR5EAE:~/workspace/demo/go$ go run main.go
main.go:5:9: package mymod/mypkg is not in std (/usr/lib/go-1.22/src/mymod/mypkg)
答案是依旧不行,因为Golang规定导入包必须满足如下类似目录结构,请参考:
.
├── go.mod
├── main.go
└── mypkg
└── pkg_va.go
2 directories, 3 files
xiongzile@LAPTOP-S6FR5EAE:~/workspace/demo/go$ go run main.go
10
现在终于可以啦!我们注意到使用了这个指令之后,我们的工程目录下多了一个文件go.mod
我们看一下里面包括什么内容:
module mymod
go 1.22.2
目前这个文件只包括了我们的module名和我们使用的go版本号。在我们尝试使用外部库的时候会出现更多内容。
接下来看一个代码示例:
// main.go
package main
import (
"github.com/gorilla/mux"
"log"
"net/http"
"os"
)
func homeHandler(w http.ResponseWriter, r *http.Request) {
log.Println("处理首页请求")
w.WriteHeader(http.StatusOK)
w.Write([]byte("欢迎来到Go Modules Web服务!"))
}
func main() {
// 使用环境变量或默认值设置日志文件
logFile, err := os.OpenFile(os.Getenv("LOG_FILE_PATH"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Fatal("打开日志文件失败:", err)
}
defer logFile.Close()
// 设置日志输出
log.SetOutput(logFile)
r := mux.NewRouter()
r.HandleFunc("/", homeHandler)
log.Println("启动Web服务:localhost:8080")
if err := http.ListenAndServe(":8080", r); err != nil {
log.Fatal("启动Web服务失败:", err)
}
}
我们尝试运行,得到了这样的结果:
xiongzile@LAPTOP-S6FR5EAE:~/workspace/demo/go$ go run main.go
main.go:4:5: no required module provides package github.com/gorilla/mux; to add it:
go get github.com/gorilla/mux
我们按照go的提示输入go get github.com/gorilla/mux
再次查看go.mod
module mymod
go 1.22.2
require github.com/gorilla/mux v1.8.1
多了一个require
关键词,结合我们刚才的操作不难理解,这个关键词是为了让我们获取外部库,并能在这个项目中运用。
到目前为止,我们就能够在我们的项目里实现对外部库和我们自己的库的调用了,接下来提供几个常用的关于go module管理的指令。
go mod init + modulename
: 初始化模块,并为当前模块命名。
go mod tidy
: 管理包,增加本地缺失的包,删除没用的包。
go mod graph
: 查看模块间依赖图
学到这里应该就能进行基本的包管理(目前是够用了),进阶的以后再慢慢学。
博主是Golang的初学者,如果有任何错误欢迎提醒我。
博主邮箱
xiongzile99@gmail.com
参考资料
https://developer.aliyun.com/article/1486997?spm=5176.26934562.main.6.215e4a0aZRNBnS