【Golang】包

Go语言是使用包来组织源代码的,包(package)是多个 Go 源码的集合,是一种高级的代码复用方案

Go语言中为我们提供了很多内置包,如 fmt、os、io 等。

任何源代码文件必须属于某个包,同时源码文件的第一行有效代码必须是package pacakgeName 语句,通过该语句声明自己所在的包

1、包的基本概念

Go语言的包借助了目录树的组织形式,一般包的名称就是其源文件所在目录的名称

虽然Go语言没有强制要求包名必须和其所在的目录名同名,但还是建议包名和所在目录同名,这样结构更清晰

包可以定义在很深的目录中,包名的定义是不包括目录路径的,但是包在引用时一般使用全路径引用

包的习惯用法:

  • 包名一般是小写的,使用一个简短且有意义的名称
  • 包名一般要和所在的目录同名,也可以不同,包名中不能包含- 等特殊符号
  • 包名为 main 的包为应用程序的入口包,编译不包含 main 包的源码文件时不会得到可执行文件
  • 一个文件夹下的所有源码文件只能属于同一个包,同样属于同一个包的源码文件不能放在多个文件夹下

2、包的导入

要在代码中引用其他包的内容,需要使用 import 关键字导入使用的包。具体语法如下:

go 复制代码
import "包的路径"

注意事项:

  • import 导入语句通常放在源码文件开头包声明语句的下面;
  • 导入的包名需要使用双引号包裹起来;

包的导入有两种写法,分别是单行导入和多行导入

go 复制代码
//单行导入
import "包 1 的路径"
import "包 2 的路径"

//多行导入
import (
    "包 1 的路径"
    "包 2 的路径"
)

注意:

包的绝对路径就是GOROOT/src/GOPATH后面包的存放路径

3、包的引用格式

  • 标准引用格式

    go 复制代码
    package main
    import "fmt"
    func main() {
        fmt.Println("hello world")
    }

    此时可以用fmt.作为前缀来使用 fmt 包中的方法,这是常用的一种方式

  • 自定义别名引用格式

    go 复制代码
    package main
    import F "fmt"
    func main() {
        F.Println("hello world")
    }

    其中 F 就是 fmt 包的别名,使用时我们可以使用F.来代替标准引用格式的fmt.来作为前缀使用 fmt 包中的方法

  • 省略引用格式

    go 复制代码
    package main
    import . "fmt"
    func main() {
        //不需要加前缀 fmt.
        Println("hello world")
    }

    这种格式相当于把 fmt 包直接合并到当前程序中,在使用 fmt 包内的方法是可以不用加前缀fmt.,直接引用

  • 匿名引用格式

    go 复制代码
    package main
    import (
        _ "database/sql"
        "fmt"
    )
    func main() {
        fmt.Println("hello world")
    }

    在引用某个包时,如果只是希望执行包初始化的 init 函数,而不使用包内部的数据时,可以使用匿名引用格式

    匿名导入的包与其他方式导入的包一样都会被编译到可执行文件中

    使用标准格式引用包,但是代码中却没有使用包,编译器会报错。如果包中有 init 初始化函数,则通过import _ "包的路径" 这种方式引用包,仅执行包的初始化函数,即使包没有 init 初始化函数,也不会引发编译器报错

  • 注意:

    • 一个包可以有多个 init 函数,包加载时会执行全部的 init 函数,但并不能保证执行顺序,所以不建议在一个包中放入多个 init 函数,将需要初始化的逻辑放到一个 init 函数里面。
    • 包不能出现环形引用的情况,比如包 a 引用了包 b,包 b 引用了包 c,如果包 c 又引用了包 a,则编译不能通过。
    • 包的重复引用是允许的,比如包 a 引用了包 b 和包 c,包 b 和包 c 都引用了包 d。这种场景相当于重复引用了 d,这种情况是允许的,并且 Go 编译器保证包 d 的 init 函数只会执行一次

4、go mod

go module 是Go语言从 1.11 版本之后官方推出的版本管理工具,并且从 Go1.13 版本开始,go module 成为了Go语言默认的依赖管理工具

Modules 官方定义为

Modules 是相关 Go 包的集合,是源代码交换和版本控制的单元

Go语言命令直接支持使用 Modules,包括记录和解析对其他模块的依赖性,Modules 替换旧的基于 GOPATH 的方法,来指定使用哪些源文件

使用go module之前需要设置环境变量:

  1. GO111MODULE=on
  2. GOPROXY=https://goproxy.io,directopen in new window
  3. GOPROXY=https://goproxy.cn,direct(国内的七牛云提供)

GO111MODULE 有三个值:off, on和auto(默认值)

  • GO111MODULE=off,go命令行将不会支持module功能,寻找依赖包的方式将会沿用旧版本那种通过vendor目录或者GOPATH模式来查找。
  • GO111MODULE=on,go命令行会使用modules,而一点也不会去GOPATH目录下查找。
  • GO111MODULE=auto,默认值,go命令行将会根据当前目录来决定是否启用module功能。这种情况下可以分为两种情形:
    • 当前目录在GOPATH之外且该目录包含go.mod文件 开启
    • 当处于 GOPATH 内且没有 go.mod 文件存在时其行为会等同于 GO111MODULE=off
  • 如果不使用 Go Modules, go get 将会从模块代码的 master 分支拉取
  • 而若使用 Go Modules 则你可以利用 Git Tag 手动选择一个特定版本的模块代码

go mod 有以下命令

命令 说明
downloadx download modules to local cache(下载依赖包)
edit edit go.mod from tools or scripts(编辑go.mod)
graph print module requirement graph (打印模块依赖图)
init initialize new module in current directory(在当前目录初始化mod)
tidy add missing and remove unused modules(拉取缺少的模块,移除不用的模块)
vendor make vendored copy of dependencies(将依赖复制到vendor下)
verify verify dependencies have expected content (验证依赖是否正确)
why explain why packages or modules are needed(解释为什么需要依赖)
  • 常用的有 init tdiy edit

使用go get命令下载指定版本的依赖包:

执行go get 命令,在下载依赖包的同时还可以指定依赖包的版本。

  • 运行go get -u命令会将项目中的包升级到最新的次要版本或者修订版本;
  • 运行go get -u=patch命令会将项目中的包升级到最新的修订版本;
  • 运行go get [包名]@[版本号]命令会下载对应包的指定版本或者将对应包升级到指定的版本。

提示:go get [包名]@[版本号]命令中版本号可以是 x.y.z 的形式,例如 go get foo@v1.2.3,也可以是 git 上的分支或 tag,例如 go get foo@master,还可以是 git 提交时的哈希值,例如 go get foo@e3702bed2

  • 项目中使用

    在 GOPATH 目录下新建一个目录,并使用go mod init初始化生成 go.mod 文件

    go.mod 文件一旦创建后,它的内容将会被 go toolchain 全面掌控,go toolchain 会在各类命令执行时,比如go getgo buildgo mod等修改和维护 go.mod 文件

    go.mod 提供了 module、require、replace 和 exclude 四个命令:

    • module 语句指定包的名字(路径);
    • require 语句指定的依赖项模块;
    • replace 语句可以替换依赖项模块;
    • exclude 语句可以忽略依赖项模块。

    初始化生成的 go.mod 文件如下所示:

添加依赖

新建一个 main.go 文件,写入以下代码

go 复制代码
package main
import (
    "net/http"
    "github.com/labstack/echo"
)
func main() {
    e := echo.New()
    e.GET("/", func(c echo.Context) error {
        return c.String(http.StatusOK, "Hello, World!")
    })
    e.Logger.Fatal(e.Start(":1323"))
}

执行go mod tidy运行代码会发现 go mod 会自动查找依赖自动下载

go module 安装 package 的原则是先拉取最新的 release tag,若无 tag 则拉取最新的 commit

go 会自动生成一个 go.sum 文件来记录 dependency tree。

执行脚本go run main.go,就可以运行项目。

可以使用命令go list -m -u all来检查可以升级的 package,使用go get -u need-upgrade-package升级后会将新的依赖版本更新到 go.mod

比如:go get -u github.com/labstack/gommon

也可以使用go get -u升级所有依赖。

使用 replace 替换无法直接获取的 package:

由于某些已知的原因,并不是所有的 package 都能成功下载,比如:golang.org 下的包。

modules 可以通过在 go.mod 文件中使用 replace 指令替换成 github 上对应的库,比如:golang.org 下的包

go 复制代码
replace (
    golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a => github.com/golang/crypto v0.0.0-20190313024323-a1f597ede03a
)

modules 可以通过在 go.mod 文件中使用 replace 指令替换成 github 上对应的库,比如:

go 复制代码
replace (
    golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a => github.com/golang/crypto v0.0.0-20190313024323-a1f597ede03a
)

go install命令将项目打包安装为可执行文件,在安装在GOPATH的bin目录下,go install执行的项目 必须有main方法

相关推荐
筑基.几秒前
basic_ios及其衍生库(附 GCC libstdc++源代码)
开发语言·c++
雨颜纸伞(hzs)15 分钟前
C语言介绍
c语言·开发语言·软件工程
J总裁的小芒果17 分钟前
THREE.js 入门(六) 纹理、uv坐标
开发语言·javascript·uv
坊钰1 小时前
【Java 数据结构】移除链表元素
java·开发语言·数据结构·学习·链表
chenziang11 小时前
leetcode hot100 LRU缓存
java·开发语言
会说法语的猪1 小时前
springboot实现图片上传、下载功能
java·spring boot·后端
时雨h1 小时前
RuoYi-ue前端分离版部署流程
java·开发语言·前端
凡人的AI工具箱1 小时前
每天40分玩转Django:实操多语言博客
人工智能·后端·python·django·sqlite
Cachel wood1 小时前
Django REST framework (DRF)中的api_view和APIView权限控制
javascript·vue.js·后端·python·ui·django·前端框架
云计算DevOps-韩老师1 小时前
【网络云计算】2024第52周-每日【2024/12/25】小测-理论&实操-自己构造场景,写5个系统管理的脚本-解析
开发语言·网络·云计算·bash·perl