Go语言之包管理

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 什么是 Go 语言中的包我们在使用其他语言,比如 Java ,是有包的概念的。它是 Java 语言中组织我们的 Java 文件的一个概念,比如java.lang这个包,它里面有很多我们常用的类,比如 String。
什么是 Go 语言中的包


我们在使用其他语言,比如 Java ,是有包的概念的。它是 Java 语言中组织我们的 Java 文件的一个概念,比如java.lang这个包,它里面有很多我们常用的类,比如 String。在 Go 语言中,包也是类似的概念。它是把我们的 Go 文件组织起来,可以方便进行归类、复用等, 比如 Go 内置的 net 包。


net
├── http
├── internal
├── mail
├── rpc
├── smtp
├── testdata
├── textproto
└── url


以上是 net 包的一个目录结构,net 本身是一个包,net 目录下的 http 又是一个包。从这个大家可以看到,Go 语言的包其实就是我们计算机里的目录,或者叫文件夹,通过它们进行目录结构和文件组织。Go 只是对目录名字做了一个翻译,叫“包”而已。比如这里的 net 包其实就是 net 目录,http 包其实就是 http 目录,这也是 Go 语言中的一个命名习惯,包名和文件所在的目录名是一样的。


包的命名


Go 语言中包的命名,遵循简洁、小写以及与 Go 文件所在目录同名的原则,这样就便于我们引用、书写和快速定位查找。


比如 Go 自带的 http 这个包,这个 http 目录下的所有 Go 文件都属于这个 http 包,所以我们使用 http 包里的函数、接口的时候,导入这个 http 包就可以了。


package main

import "net/http"

func main() {
    http.ListenAndServe("127.0.0.1:80",handler);
}


从这个例子可以看到,我们导入的是net/http,这在 Go 语言里叫做全路径。因为 http 包在 net 里面,net 是最顶级的包,所以必须使用全路径导入,Go 编译程序才能找到 http 这个包,和我们文件系统的目录路径是一样的。


因为有了全路径,所以命名的包名可以和其他库的一样,只要它们的全路径不同就可以了。使用全路径的导入,也增加了包名命名的灵活性。


对于个人或者公司开发的程序而言,我们一般采用域名作为顶级包名的方式,这样就不用担心和其他开发者包名重复的问题了,比如我的个人域名是www.flysnow.org,那么我自己开发的 Go 程序都以flysnow.org作为全路径中的最顶层部分。例如,导入我开发的一个工具包:


package main

import "flysnow.org/tools"


如果你没有自己的域名,怎么办呢?这时候可以使用 Github.com 。干研发这一行的,在 Github 都会有个账号,如果没有赶紧申请一个。这时候我们就可以使用github.com/<username>作为你的顶级路径了,别人是不会和你重名的。


package main

import "github.com/rujews/tools"


这就是换成 Github.com 命名的方式。


main包


当把一个 Go 文件的包名声明为main时,就等于告诉 Go 编译程序,我这个是一个可执行的程序,那么 Go 编译程序就会尝试把它编译为一个二进制的可执行文件。


一个main的包,一定会包含一个main()函数,这种我们也不陌生,比如 C 和 Java 都有main()函数,它是一个程序的入口,没这个函数,程序就无法执行。


在 Go 语言里,同时要满足main包和包含main()函数,才会被编译成一个可执行文件。


我们看一个 Hello World 的 Go 语言版本,来说明main 包。


package main

import "fmt"

func main() {
    fmt.Println("Hello, 世界")
}


假设该 Go 文件叫 hello.go,放在$GOPATH/src/hello目录下,那么我们在这个目录下执行go build命令就会生成二进制的可执行文件,在 window 系统下生成的是hello.exe;在 UINX、MAC 和 Linux 下生成的是hello,我们在 CMD 或者终端里执行它,就可以看到控制台打印的:


Hello, 世界


二进制可执行文件的名字,就是该 main 包的 Go 文件所在目录的名字,因为 hello.go 在 hello 目录下,所以生成的可执行文件就是 hello 这个名字。


导入包


要想使用一个包,必须先导入它才可以使用。Go 语言提供了import关键字来导入一个包,这个关键字告诉 Go 编译器到磁盘的哪里去找要想导入的包,所以导入的包必须是一个全路径的包,也就是包所在的位置。


import "fmt"


这就表示我们导入了fmt包,也就等于告诉 Go 编译器,我们要使用这个包下面的代码。如果要导入多个包怎么办呢?Go 语言还为我们提供了导入块。


import (
    "net/http"
    "fmt"
)


使用一对括号包含导入块,每个包独占一行。


对于多于一个路径的包名,在代码中引用的时候,使用全路径最后一个包名作为引用的包名,比如net/http,我们在代码使用的是http,而不是net


现在我导入了包,那么编译的时候,Go 编译器去什么位置找它们呢?这里就要介绍一下 Go 的环境变量了。Go 有两个很重要的环境变GOROOTGOPATH,这是两个定义路径的环境变量,GOROOT是安装 Go 的路径,比如/usr/local/goGOPATH是我们自己定义的开发者个人的工作空间,比如/home/flysnow/go。 


编译器会使用我们设置的这两个路径,再加上import导入的相对全路径来查找磁盘上的包,比如我们导入的fmt包,编译器最终找到的是/usr/local/go/fmt这个位置。


值得了解的是:首先,对于包的查找是有优先级的,编译器会优先在GOROOT里搜索;其次是GOPATH,一旦找到,就会马上停止搜索。如果最终都没找到,那么就报编译异常了。


远程包导入


互联网的时代,现在大家使用类似于 Github 共享代码的越来越多,如果有的 Go 包共享在 Github 上,我们一样有办法使用它们,这就是远程导入包了,或者是网络导入,Go 天生就支持这种情况,所以我们可以很随意地使用 Github 上的 Go 库开发程序。


import "github.com/spf13/cobra"


这种导入,前提必须是该包托管在一个分布式的版本控制系统上,比如 Github、Bitbucket 等,并且是 Public 的权限,可以让我们直接访问它们。


编译在导入它们的时候,会先在GOPATH下搜索这个包,如果没有找到,就会使用go get工具从版本控制系统(GitHub)获取,并且会把获取到的源代码存储在GOPATH目录下对应 URL 的目录里,以供编译使用。


go get工具可以递归获取依赖包,如果github.com/spf13/cobra也引用了其他的远程包,该工具可以一并下载下来。


命名导入


我们知道,在使用import关键字导入包之后,我们就可以在代码中通过包名使用该包下相应的函数、接口等。如果我们导入的包名正好有重复的怎么办呢?针对这种情况,Go 语言可以让我们对导入的包重新命名,这就是命名导入。


package main

import (
    "fmt"
    myfmt "mylib/fmt"
)

func main() {
    fmt.Println()
    myfmt.Println()
}


如果没有重新命名,那么对于编译器来说,这两个fmt它是区分不清楚的。重命名也很简单,在我们导入的时候,在包名的左侧,起一个新的包名就可以了。


Go 语言规定,导入的包必须要使用,否则会包编译错误,这是一个非常好的规则,因为这样可以避免我们引用很多无用的代码而导致的代码臃肿和程序的庞大。很多时候,我们都不知道哪些包是否使用,这在 C 和 Java 上会经常遇到,因此我们不得不借助工具来查找我们没有使用的文件、类型、方法和变量等,把它们清理掉。


但是有时候,我们需要导入一个包,但是又不使用它,按照规则,这是不行的,为此 Go 语言给我们提供了一个空白标志符 _ ,只需要我们使用 _ 重命名我们导入的包就可以了。


package main

import (
    _ "mylib/fmt"
)


包的 init ()函数


每个包都可以有任意多个init()函数,这些init()函数都会在main()函数之前执行。init()函数通常用来做初始化变量、设置包或者其他需要在程序执行前的引导工作。比如上面我们讲的需要使用 _ 空标志符来导入一个包的目的,就是想执行这个包里的init()函数。


我们以数据库的驱动为例,Go 语言为了统一关于数据库的访问,使用databases/sql抽象了一层数据库的操作,可以满足我们操作 MYSQL、Postgre 等数据库。这样不管我们使用这些数据库的哪个驱动,编码操作都是一样的,想换驱动的时候,就可以直接换掉,而不用修改具体的代码。


这些数据库驱动的实现,就是具体的,可以由任何人实现的,它的原理就是定义了init()函数,在程序运行之前,把实现好的驱动注册到 sql 包里,这样我们就使用使用它操作数据库了。


package mysql

import (
    "database/sql"
)

func init() {
    sql.Register("mysql", &MySQLDriver{})
}


因为我们只是想执行这个 mysql 包的init()方法,并不想使用这个包,所以我们在导入这个包的时候,需要使用_重命名包名,避免编译错误。


import "database/sql"
import _ "github.com/go-sql-driver/mysql"

db, err := sql.Open("mysql", "user:password@/dbname")


看非常简洁,剩下针对的数据库的操作都是使用的database/sql标准接口。如果我们想换一个 mysql 的驱动的话,只需要换个导入就可以了,灵活方便,这也是面向接口编程的便利。


相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
打赏
0
0
0
0
9
分享
相关文章
Go语言环境搭建
Go语言环境搭建
|
7月前
|
GVM:Go语言版本和包管理的神器!
GVM,Go版本管理器,简化了在单机上切换不同Go版本的任务。
170 0
【Go语言专栏】理解Go语言的包管理机制
【4月更文挑战第30天】Go语言包管理是构建可维护应用的关键,从基本概念如包导入、初始化到版本管理和依赖管理,再到Go Modules的引入,简化了过程。包的可见性规则和社区生态也至关重要。理解并掌握这些机制对于编写高质量Go代码具有决定性影响。随着Go语言的持续发展,包管理将更加强大易用。
149 0
go语言下载安装
go语言下载安装
164 0
|
8月前
|
Go
go语言安装及其环境配置
go语言安装及其环境配置
78 0
万事开头难-go语言的安装及环境配置
万事开头难-go语言的安装及环境配置
241 0
万事开头难-go语言的安装及环境配置
Day 1——Go语言环境配置
Go! Go! 一起来学习Go语言
251 0
 Day 1——Go语言环境配置
Go语言系列:如何搭建Go语言开发环境?
从【Go 语言系列:Go 从哪里来,Go 将去哪里?】这篇文章开始,我们将探索Go语言的魅力,一层一层的剥开它的心,然后吃透它搞定它。今天就将开启Go语言入门的相关基础知识学习,学习一门新的语言还得为其搭建开发环境,这样才能驾驭住它。
139 0
1.1Go语言安装
一、下载网址 1.官网:golang.org 2.国内下载:studygolang.com/dl
GO语言 第三方库
个人常用的一些好用的GO语言第三方库: Excel: github.com/360EntSecGroup-Skylar/excelize Yaml: gopkg.in/yaml.v2 PostgreSQL github.com/lib/pq
833 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等