本文为《Go in Action》的第三章读书笔记。
第二章主要是介绍package和工具相关的事情。
package
翻译一下就是包
Q: 什么是package?有什么用?
A: 原文:
All Go programs are organized into groups of files called packages, so that code has the ability to be included into other projects as smaller reusable pieces.
package就是a group of file。也就是一组文件。其作用就是package作为一个可重用的代码片段,被其他项目所使用。
Q: package如何定义?
A: 几点:
- 每个文件的第一行使用
pakage
定义package。这里的第一行指的是除了空行和注释的第一行。也就是说package那一行的上面还可以有注释或者空行,但是不能有其他代码。 - 同一个文件夹下面不能有多个package。
- 同一个package不能跨多个文件夹。
- 一个文件夹下面的所有文件必须属于同一个package。
- 通用做法是:文件夹的名字就是package的名字
- package的名字应当是简洁的小写字母
- 在代码中调用pacakge里面的东西时,默认使用pakage的名字,不过也可以覆盖。当你引入多个package,其名字是一样的时候,就需要覆盖了。
Q: package main特殊性?
A: 如下:
- 告诉go的命令,需要将文件编译成为可执行文件
- package main里面必须要有main函数
Q: go的hello world怎么写?
A: 如下:
- 首先在$GOPATH/src目录下,建立hello文件夹
- 创建hello.go文件
- 写入如下内容:
package main
import "fmt"
func main() {
fmt.Println("Hello World!")
}
- 在hello文件夹下运行
go build
,会生成一个hello的可执行文件 - 运行该可执行文件,输出Hello World
Q: pacakge如何引入?
A: 简单来说,就是使用import "
这个语法。
单行:
import "fmt"
多行:
import (
"fmt"
"strings"
)
如下:
- import寻找的路径是go环境使用目录的相对路径
- 标准库里面的import路径是在go的安装路径下,比如可能是/usr/local/go
- 其余的库的import路径是在GOPATH下
- 首先会从go的安装路径下去找
两个特殊点的import:
显示声明名字:
import (
fmt
myfmt from "mylib/fmt"
}
使用下划线(称为blank identifier):
import (
fmt
_ from "mylib/nothing"
)
remote imports
当import的内容是比如“github.com/spf13/viper”的时候,可以使用go get
命令获取远程包到对应的目录下,以让本地可以用。
go get
还是recursive的,即可以下载包及其依赖。
init函数
原文:
Each package has the ability to provide as many init functions as necessary to be invoked at the beginning of execution time. All the init functions that are discovered by the compiler are scheduled to be executed prior to the main function being executed.
When a program imports this package, the init function will be called
每个包可以有多个init函数(没明白...)。每个init函数都会在main函数被调用前执行。具体执行时间是在包被import的时候。
使用go tools
go的几个命名:
go #打印g的帮助信息
go build hello.go #编译hello.go,生成可执行文件
go clean hello.go #清理生成的文件
go build github.com/goinaction/code/chapter3/wordcount
go build github.com/goinaction/code/chapter3/...
go build wordcount.go
go build .
go run wordcount.go
go vet main.go #检查代码错误
go format main.go
go doc tar
godoc -http=:6060 #
给package加注释,注释会展示在go doc中:
/*
Package usb provides types and functions for working with USB devices. To connect to a USB device start by creating a new USB connection with NewConnection ...
*/
package usb
分享代码
几条:
- 代码可以上传到github,在github的repository的根目录直接创建package。不要建什么code或者src,这样import的时候路径会比较长
- package可以是很小的,实现简单的功能,只有些许代码
- 使用
go fmt
格式化代码 - 给代码加注释
依赖管理
简单来说就是管理go的依赖包
什么是可重复制作(reproducible)?
简单来说,就是在我的电脑上编写的代码,在你的电脑上依然是同样的东西。为什么不一样呢?比如我们的代码存放位置不同,引用的import路径不同,引用的库的版本不同等。
vendoring
原文:
Community tools such as godep and vendor have solved the dependency problem by using a technique called vendoring and import path rewriting. The idea is to copy all the dependencies into a directory inside the project repo, and then rewrite any import paths that reference those dependencies by providing the location inside the project itself.
简单翻译:社区的一些如godep和vendor的工具在解决依赖问题的时候,使用了一种称为vendoring和重写import路径的技术。大意为将所有的依赖拷贝到项目中的一个目录下,然后重写所有的import路径,指向项目内部的那些拷贝过来的包。
这样项目使用到的所有代码都在项目目录下了,直接zip一下就包含了源文件和引用到的其他库文件了。
在vendor前:
package main
import (
"bitbucket.org/ww/goautoneg"
"github.com/beorn7/perks"
)
vendor之后:
package main
import (
"github.ardanstudios.com/myproject/Godeps/_workspace/src/ bitbucket.org/ww/goautoneg"
"github.ardanstudios.com/myproject/Godeps/_workspace/src/ github.com/beorn7/perks"
)
gb
原文:
Gb is a whole new class of build tool being developed by members of the Go community. Gb takes a different approach to solving the reproducible-build problem, which starts with the understanding that wrapping the Go tooling is not an option.
gb代表了一类新的构建工具,其表示对go tooling进行又一层封装,并不是解决reproducible问题的一种可选项。
The philosophy behind gb stems from the idea that Go doesn’t have reproducible builds because of the import statement. The import statement drives go get, but import doesn’t contain sufficient information to identify which revision of a package should be fetched any time go get is called. The possibility that go get can fetch a different version of code for any given package at any time makes supporting the Go tooling in any reproducible solution complicated and tedious at best.
gb认为go无法保证reproducible builds的原因在于import。因为go get从import获取信息,但是import并没有表示包版本的信息,所以go get也不知道获取哪个特定版本的库,很有可能获取了一个不同版本的依赖库。
A gb project is simply a directory on disk that contains a subdirectory named src/. The symbol $PROJECT refers to the root directory on disk where the src/ directory is located and is only used as a shortcut for describing the location on disk for the project.
一个gb的项目简单来说就是一个具有src子目录的目录,也就是一个目录下面有一个叫src的子目录。$PROJECT指向了该目录的路径。
Gb projects differentiate between the code you write and the code your code depends on. The code your code depends on is called vendored code. A gb project makes a clear distinction between your code and vendored code.
Gb规定用户编写的代码叫code,其依赖的代码叫vendored code。其存放路径为:
$PROJECT/src
$PROJECT/vendor/src
gb不需要改动源码里面的import的路径。
The gb tool will look inside the PROJECT/src/ directory first. The entire source code for the project is located within a single repo and directory on disk, split between the src/ and vendor/src/ subdirectories.
gb工具会去PROJECT目录下。
这些目录结构的约定都是gb自己定的,go工具不认识,因此不能使用go工具,需要使用gb这个工具。比如编译一个项目:
gb build all