Go语言编程笔记11:使用包组织代码
Go语言的代码是以包的形式组织的,本篇笔记将阐述包相关的一些内容。
基本概念
创建
环境变量
Go有两个和包相关的系统环境变量:GOROOT
和GOPATH
。前者是Go语言本身的安装目录,后者是用户的“Work Space”,也就是一般的编写代码的目录。
这两个目录都主要由以下三个字目录构成:
- bin:二进制可执行文件。
- pkg:编译后的包组件。
- src:源码。
对于GOROOT
的目录来说,子目录所对应的内容都是Go语言本身的内容,比如bin
下有go.exe
和gofmt.exe
,前者是Go的主要工具,编译和执行Go程序都要靠它,后者可以格式化代码。src
下则存放Go的标准库的源码,Go是一个开源语言,所以自身相关的所有组件都可以以源码的形式保存在这里。
和GOROOT
类似,GOPATH
下的src
目录存放用户编写的代码。
在Windows下,安装Go的安装包后会自动创建环境变量GOPATH
,并设置为C盘用户目录下的子目录go
。如果需要自定义代码编写目录,可以直接修改用户环境变量中的GOPATH
。
如果要检查GOPATH
是否设置正确并生效,可以在命令行下执行:
❯ go env
...省略
set GOPATH=D:\workspace\go
如果指向的目录下缺少
src
子目录,需要手动创建。
命名规则
按照Go的命名习惯,包名的命名需要符合以下规则:
- 全部为小写字母组成,中间不应该使用连字符或下划线,如果是两个单词组成,直接连接,比如
strconv
。 - 应该在没有歧义的情况下尽量使用简写,比如
fmt
。 - 包名应当与代码所在的目录尽量保持一致。
确定好包名后,在GOPATH
指向的目录下的src
目录中就可以用包名创建目录,作为存放包代码的目录。
包中的代码文件命名和数量都没有规定,可以开发者自行决定。
包级常量、变量
可以在函数外创建包级常量或变量:
package pkgvar
var Num1 int
var Num2 int
const pi float32 = 3.14
可以在包内的函数或者包外访问这些包级变量。
init函数
有些包需要在被导入时进行一些初始化行为,这些内容可以通过init
函数实现:
package pkgvar
var Num1 int
var Num2 int
const pi float32 = 3.14
func init() {
Num1 = 1
Num2 = 2
}
进行测试:
package main
import (
"fmt"
"go-notebook/ch11/pkgvar"
)
func main() {
fmt.Println(pkgvar.Num1)
fmt.Println(pkgvar.Num2)
// 1
// 2
}
导入
可以使用import
导入包,对于标准包,可以直接导入:import "fmt"
。对于第三方包,需要按照在GOPATH
下的目录结构进行导入:import "go-notebook/ch11/pkgvar"
。
重命名导入
如果导入的包和当前代码文件中的变量名出现重复,则需要在导入时重新命名:
package main
import (
"fmt"
pkgv "go-notebook/ch11/pkgvar"
)
func main() {
var pkgvar string
fmt.Println(pkgvar)
fmt.Println(pkgv.Num1)
fmt.Println(pkgv.Num2)
// 1
// 2
}
匿名导入
在某些时候,可能需要导入一个包,但并不需要在当前代码中使用,比如说在系统刚启动时,对负责管理当前系统的配置的包进行初始化:
package config
var Configs map[string]interface{}
func init() {
Configs["version"] = "1.0.0"
}
此时可以使用匿名变量_
作为包的导入名称:
package main
import (
_ "go-notebook/ch11/config"
)
func main() {
}
分发代码
当你编写好代码后,需要考虑如何将代码分发给他人,有一些编程语言在这方面很出色,比如Python,自带一个第三方库的分发平台pypi.org,可以很方便地分发代码。
Go的分发方式相对简单,只要将代码上传到Git协议的代码仓库,就可以借用git工具来上传和下载代码。
上传
这里以Github为例,详细的使用信息见从零开始Github。
下载
下载代码可以通过Go自带的工具go get
进行,不过前提是已经安装好了git
工具:
❯ go get github.com/icexmoon/go-notebook/
正常情况下,go工具会自动从指定的代码仓库下载源码到GOPATH
下的相应目录,无论当前的工作目录是什么。
如果无法下载,需要检查你电脑的网络,比如如果对命令行git
使用了代理,以访问Github,则可能需要关闭go
工具的代理:❯ go env -w GO111MODULE=off
,某些情况下这两者是有冲突的。
理论上go get
很好用,不仅会下载目标代码,还会一同下载关联的第三方代码,但实际使用时因为众所周知的缘故可能会出现各种各样的问题,如果实在无法使用,可以尝试直接使用git工具。
安装
一般情况下我们可以通过go build
对当前目录下的go
程序进行编译,并生成相应的可执行文件:
❯ go build main.go
❯ .\main.exe
1
2
这样做有个缺陷是生成的可执行文件和源码混杂在一起,并且让直接使用该程序变得麻烦,毕竟需要每次使用前都要切换到对应目录下才行。
除了上面的方式以外,我们可以直接安装目标程序到GOPATH
的bin
目录:
❯ go install github.com/icexmoon/go-notebook/ch11/main1
❯ main1
1
2
go install
可以自动检测指定的目录下的 go 代码的入口函数,进行编译后安装到$GOPATH/bin
目录,并且以所在包的名字进行命名。
这里方便起见我添加了
$GOPATH/bin
目录到用户环境变量path
中,这样就可以直接在命令行执行通过go install
安装的任何程序。
查看包文档
代码的注释相当重要,某些情况下甚至比代码本身更重要。所以我们需要明确如何正确地编写Go的注释和查看注释。
编写注释
这里以一个简单的包作为示例:
//Package input read string from keyboard
package input
import (
"bufio"
"os"
)
//GetLine will read a line from keyboard and return
func GetLine() (string, error) {
scanner := bufio.NewReader(os.Stdin)
return scanner.ReadString('\n')
}
包注释需要编写在源码文件的最上方,package
声明之前,需要注意的是,即使该包是由多个源码文件组成,也仅需要在其中一个源码中写入包注释。
如果包注释的内容较多(超过三行),可以在包中添加一个文件doc.go
来专门存放包注释。
包注释按照惯例以Package pkg_name xxx
开头,其中pkg_name
应当替换为包名。
函数注释卸载函数定义的上方,按惯例以函数名称开头,比如示例中的GetLine xxx
。
通常我习惯于在函数注释中加入参数和返回值的相关说明。
使用go doc查看文档
使用go doc
工具可以查看包相关的注释文档:
❯ go doc input
package input // import "github.com/icexmoon/go-notebook/ch11/input"
Package input read string from keyboard
func GetLine() (string, error)
根据注释自动生成的文档信息中,最开头是包名及导入路径,下边是包的解释信息,此外还会包含包中的函数。
可以进一步查看某个函数的相关文档:
❯ go doc input.GetLine
package input // import "github.com/icexmoon/go-notebook/ch11/input"
func GetLine() (string, error)
GetLine will read a line from keyboard and return
通过go doc
不仅可以查看自己编写的文档,实际上可以查看所有标准库以及下载的第三方包的文档:
❯ go doc bufio
package bufio // import "bufio"
Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer
object, creating another object (Reader or Writer) that also implements the
interface but provides buffering and some help for textual I/O.
...
使用浏览器查看文档
使用godoc
工具可以通过浏览器查看注释文档,这点在Go语言编程笔记1:Hello World中已经有过说明,就不再重复。
谢谢阅读。