Pinvon's Blog

所见, 所闻, 所思, 所想

Go实战(一) 环境搭建

1

2 Ubuntu 16.04 + Go

下载Go语言压缩包.

Go官网

Go中国

tar -C /usr/local -xzf go1.9.linux-amd64.tar.gz

2.1 配置环境变量

/etc/profile 是针对所有用户, 登录时读取, 重启才能生效.

~/.profile 针对当前用户, 登录时读取, 使用 source 命令即可生效.

~/.bashrc 针对当前用户, 打开 bash shell 时读取, 使用 source 命令即可生效.

这边, 我们把环境变量配置到 ~/.profile 中.

打开 ~/.profile, 在文件末尾添加如下代码:

export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin

使用 source ~/.profile 使配置生效.

GOROOT 表示 Go 的安装目录, 这样我们开发 Go 的 IDE 就可以自动找到我们的 Go 安装目录, 自动配置 Go SDK.

第2句把 /usr/local/go/bin 目录添加到 PATH 中, 这样可以在终端直接使用 go 命令.

2.2 设置工作目录

目录目录是我们用来存放开发时的源码的地方. 我们使用 GOPATH 来保存这个变量, 写入到 ~/.profile 中.

打开 ~/.profile, 在末尾添加:

export GOPATH=$HOME/go
export PATH=$GOPATH/bin:$PATH

使用 source ~/.profile 使配置生效.

在 GOPATH 目录下, 一般有三个子目录, 如果没有, 则自己新建一下. 如下图所示:

0.png

其中

  • bin: 存放 go install 命令生成的可执行文件, 我们在上面已经将其路径加入到 PATH 环境变量中了, 这样可以直接在终端使用我们Go开发生成的程序.
  • pkg: 存放 Go 编译生成的文件.
  • src: 存放 Go 源代码, 不同工程项目的代码以包名区分.

2.2.1 src目录

这里再对 src 目录进行讨论.

如果我们有多个项目, 就要使用包名来组织我们的目录结构. 一般如果包名使用网站域名开头, 就不会有重复. 如: github.com 开头, 后面再加上自己的用户名. 如下图所示:

1.png

如果我们要引用一个包, 可以通过包路径来引入. 包路径就是从 src 目录开始的. 如:

import (
    "github.com/hyperledger/fabric/core/chaincode/shim"
)

shim 目录下, 有许多 .go 文件.

2.2.1.1 test

3 Hello World

新建自己的工程目录: mkdir -p $GOPATH/src/github.com/pinvondev/hello.

进入自己的工程目录.

新建文件 main.go, 代码如下:

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello World")
}

3.1 运行

在 $GOPATH/src/github.com/pinvondev/hello 目录下, 运行 go run main.go, 就可以看到打印的 Hello World 了.

package 是关键字, 定义一个包, 和 Java 中的 package 一样, 是模块化的关键.

  • main包: 这是一个特殊的包名, 它表示当前是一个可执行程序, 而不是一个库.
  • import: 关键字, 表示要引入的包, 只有引入后, 才能被使用.
  • fmt包: 引入这个包后, 我们就可以使用它的函数了.
  • main(): 主函数, 表示程序执行的入口.
  • Println(): fmt 包中的函数, 用于打印输出.

3.2 安装

安装的意思就是生成可执行程序, 我们可以使用 go install 命令, 将程序安装到 $GOPATH/bin 目录下:

go install github.com/pinvondev/hello

安装成功以后, 我们直接在终端执行 hello 命令, 就可以打印出 Hello World 了.

3.3 跨平台编译

查看编译环境: go env, 结果类似下图:

2.png

其中, GOOS 指的是目标操作系统, GOARCH 指的是目标处理器的架构. 这两个变量可指定的值都定义在了 $GOROOT/src/go/build/syslist.go 里面. 如图所示:

3.png

这两个变量的值的组合, 可参考文档: $GOROOT/doc/install-source.html 如下图所示:

4.png

具体编译的时候, 比如要生成 linux 64 位的程序, 可以这样:

GOOS=linux GOARCH=amd64 go build github.com/pinvondev/hello

这样的好处是, 环境变量的更改只对本次运行有效, 不会更改我们的默认配置.

4 获取远程包

go get 命令可以获取远程包, 参数是完整的包名.

go get -v github.com/derekparker/delve/cmd/dlv

这样, 这个库就可以下载到 $GOPATH/src 目录下了. 后面使用的时候, 可以直接像导入其他包一样来导入.

go get 命令的本质是使用了版本控制工具(如 git)来下载, 所以在使用之前, 必须确保安装了这些版本控制工具.

如果远程包有更新, 可以用 -u 参数来进行更新. 如:

go get -u -v ...

知道原理之后, 由于 google 的东西很多被墙, 如果使用 go get 下载不下来, 也可以使用浏览器下载, 然后放到 $GOPATH/src 目录下, 再进行安装.

5 Go 包管理

Go 语言自带的包, 放在 $GOROOT/src 目录里, 引入的时候省略 $GOROOT/src, 如下所示:

import "net/http"

Go 会到 $GOROOT/src 中寻找 net/http.

如果要引入自定义的包, 有两种方式:

  • 相对路径(不建议): import "./model"
  • 绝对路径: import "github.com/pinvondev/tools". Go 会到 $GOPATH/src 目录下寻找相应的包.

Go 会优先到 GOROOT 里搜索, 如果没找到, 再到 GOPATH 里搜索, 如果还没找到, 则到托管该代码的远程服务器下载, 但是如果远程服务器也没找到, 就会报错.

5.1 main 包

如果把一个 go 程序的包名声明为 main 时, 就等于告诉 go 编译器, 这是一个可执行程序, 于是 go 编译器就会尝试将其编译成一个二进制的可执行文件.

main 包, 必须包含程序的入口函数 main(). 在 main 包的 go 程序目录下, 执行 go build, 可以生成一个可执行文件. 跟 go install 生成的文件是一样的, 只是 go build 生成的文件不放在 $GOPATH/bin 目录下.

5.2 包名重复

如果我们导入的包名重复了, 可以对包名进行重命名. 如:

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

5.3 导入一个不使用的包

Go 语言规则, 导入的包必须要使用, 否则会编译错误. 如果非要导入一个不使用的包, 则把包重命名为空白标志符"_", 如下:

import (
    _ "mylib/fmt"
)

5.4 包的 init()

每个包都可以有任意数量的 init(), 这些 init() 会在 main() 之前执行, 用来初始化变量, 设置包, 或其他需要在程序执行前的引导工作. 如之前的导入一个不使用的包, 就是想执行那个包里的 init().

以数据库的驱动为例, Go 统一了关于数据库的访问, 使用 databases/sql 抽象了一层数据库的操作, 无论我们使用的数据库是 MySQL, 还是 Postgre, 还是别的, 都可以使用同样的程序来访问. 这个原理就是在 init() 里面, 把实现好的驱动注册到 sql 包里, 这样我们就直接使用它来操作数据库了.

首先, 我们创建一个包, 把相应的数据库驱动注册到包里:

package mysql
import (
    "database/sql"
)
func init() {
    sql.Register("mysql", &MySQLDriver{})
}

然后, 在需要使用数据库操作的地方, 这么写:

import "database/sql"
import _ "github.com/pinvondev/mysql"
db, err := sql.Open("mysql", "user:password@dbname")

这边, 我们对 mysql 包进行重命名, 只执行里面的 init(). 以后, 我们只需要利用 sql 进行操作, 不用考虑具体的数据库是哪个.

6 go 命令

在终端输入 go, 可以看到 go 命令的解释.

在终端输入 go help command, 可以看到关于该 command 的介绍. 如 go help build

6.1 go build

使用方法:

usage: go build [-o output] [-i] [build flags] [packages]
go build
go build hello.go

这两条命令等价, 都是使用当前目录编译.

go build 本质上需要一个路径作为参数, 让编译器可以找到哪些需要编译的 go 文件. packages 就是一个路径. 如:

go build github.com/pinvondev/hello

通配符 ... 表示匹配所有字符串, 所以:

go build github.com/pinvondev/hello/...

该命令表示编译 github.com/pinvondev/hello 目录下的所有包.

6.2 go clean

可以使用一个包(路径)作为参数.

该命令可以清理我们编译时生成的文件:

go clean

6.3 go run

该命令在 go build 之后, 自动执行可执行文件.

6.4 go env

查看 go 环境信息.

6.5 go install

该命令把生成的可执行文件或者库安装到对应的目录下.

6.6 go get

该命令从网上下载或更新指定的包及依赖包, 并对它们进行编译和安装.

-u: 更新

-v: 显示进度及调试信息

6.7 go fmt

该命令可以对源代码进行格式化, 得到和 Go 源代码一样的风格.

6.8 go vet

检查代码中的错误.

6.9 go test

go test 命令对文件有一些要求:

  • 文件名要以 _test.go 结尾
  • 测试文件中要包含若干测试函数
  • 测试函数要以 Test 为前缀, 接收 *testing.T 类型的参数

6.10 go doc

6.10.1 本地浏览API文档

godoc -http=:6060

然后就可以打开浏览器, 输入 localhost:6060 就可以访问了.

6.10.2 生成自己的文档

文档就是注释. Go 的注释与 C++ 相同.

写完注释后, 在终端进入当前目录, 输入 go docgodoc, 就可以看到注释的文档了.

6.10.3 添加文档示例

  1. 示例代码必须单独存放在一个文件中.
  2. 在这个 go 文件中, 定义一个名字为 Example() 的函数, 参数为空.
  3. 示例的输出采用注释的方式, 以 //Output: 开头, 真正的输出另起一行, 每行输出占一行.

Comments

使用 Disqus 评论
comments powered by Disqus