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语言不一样,他们的区别绝对不是includeimport 不同写法的区别。

首先展示一下我把importinclude用遇到的问题

文件目录:

.
├── 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

posted @ 2024-06-06 23:17  Withm  阅读(17)  评论(0编辑  收藏  举报