Go 工作空间 深度解析
介绍
这篇文档举例证明了一个简单地 Go package 并且介绍了 go tool
,标准的方法来 fetch, build,and install Go package and commands.
如果要使用 go tool,那么就必须将代码组织成一种特殊的形式。 请仔细的阅读这篇文档,它会教你采用最简单的方法来安装运行你的Go程序。
Workspace 工作空间
Golang 工作空间 :编译工具对源码目录有严格要求,每个工作空间 (workspace) 必须由 bin、pkg、src 三个目录组成。
Go tool 被设计成用来开源公共仓库中的代码,尽管或许你不需要发布你的代码, 但是环境的设置还是一样的。
Go的源代码必须存放在 workspace中。 workspace 是一个目录(directory hierachy),在这个目录下有三个子目录
src
包含 Go 源代码文件, 源代码文件组织成 packages (one package per directory)pkg
包含 package objects (二进制的包)bin
包含 可执行的命令 command(可执行的二进制文件)
go tool 编译(build) 源代码文件(source packages),并且将 resulting binaries 安装在 pkg
和 bin
目录下面。
src 目录下面包含多个 版本控制的仓库, (比如 Git 或者 Mercurial) 用来 跟踪一个或者多个 source package的开发进度。
下面给你一个真实环境中的 workspace 是什么样子的:
bin/
hello # 可执行的命令
outyet # 可执行的命令
pkg/
linux_amd64/
github/golang/example/
stringutil.a # pakcage objects
src/
github.com/golang/example/
.git/ # git repository metadata
hello/
hello.go # command source
outyet/
main.go # command source
main_test.go # test source
stringuitl/
reverse.go # package source
reverse_test.go # test source
这个工作空间 包含一个 代码仓库repository( example仓库),example 仓库由两个命令 command (hello, outyet)和一个库library组成(stringutil)
一个典型的 workspace 会包含多个 source repositories,包含很多 pakcages 和 commands。
大部分的 Go programmers 会 keep all their Go source code and dependencies in a single workspace. (将所有的Go源代码和依赖保存在一个工作空间中)。
另外 从上述例子中也可以看到, bin/ 中命令的名字,pkg/中库的名字 都是文件夹的文字。 src/中包的名字和你 import 时候的名字不一定一样,这一点要区别。
GOPATH 环境变量
GOPATH
环境变量 指明了 你的工作空间的位置。 它很可能是你在编写Go代码的时候需要唯一设置的环境变量。
开始编程:
1. 创建一个工作空间目录。
2. 设置 GOPATH 环境变量。
GOPATH目录可以是任意的,唯一的要求是不能是你安装Go时的目录(/usr/local/go)。
$ mkdir $HOME/go
$ export GOPATH=$HOME/go
为了方便,将工作空间的 bin 子目录 加入到 你的 PATH
环境变量中。
$ export PATH=$PATH:$GOPATH/bin
第一个 program
为了编译和运行一个简单地程序,首先选择一个 package path(这里使用 github.com/usr),创建一个 package directory (包目录)
$ mkdir $GOPATH/src/github.com/usr/hello
第二:在包目录下创建一个文件 名为 hello.go
,包含如下的代码
package main import "fmt" func main() {
fmt.Println("Hello, World.\n")
}
第三: 使用 go tool 来 build and install 这个程序
$ go install github.com/user/hello
注意: 你可以你的计算机的任何文件夹下面运行这个命令。 go tool
会在 $GOPATH
指定工作空间下面搜索 github.com/usr/hello
这个包,并且编译安装这个包。
当然, 如果你在 package directory 下面运行 go install
你就可以忽略 package path。
$ cd $GOPATH/github.com/usr/hello
$ go install
这个命令会 build the hello
command, 产生一个可执行的二进制文件。然后将这个可执行的二进制文件安装到工作目录的 bin
目录下面,文件名称为 hello
(在Windows下面为 hello.ext
,可以看到可执行二进制文件名称和目录的名称保持一致)。 在我们的例子中是: $GOPATH/bin/hello
,也就是 $HOME/go/bin/hello
当有错误发生的时候,go tool
只会 print output,而不会产生二进制文件。 如果这些命令没有产生 output(输出),就表示他们运行成功了。
现在你可以 通过输入 hello
命令的全名 来运行这个命令了
$ $GOPATH/bin/hello
hello, world
或者如果你已经将 $GOPATH/bin
加入到 PATH
中:
$ hello
hello, world
如果你使用源代码版本控制系统,现在这是一个好的时机来 initialize a repository, add the files,and commit you first chagne. Again, this step is optional: you do not need to use source control to write Go code.
$ cd $GOPATH/src/github.com/usr/hello
$ git init
Initialized empty Git repository in /home/user/go/src/github.com/user/hello/.git/
$ git add hello.go
$ git commit -m "initial commit"
[master (root-commit) 0b4507d] initial commit
file chagned, insertion(+)
create mode hello.go
将代码 Push 到远程的仓库留作读者作为一个联系吧。
第一个 Library
现在我们写一个 Library,并且在 hello 程序中使用这个库。
- 首先, 选择一个 package path (我们使用
github.com/user/stringutil
),创建这个 package directory
$ mkdir $GOPATH/src/github.com/usr/stringutil
- 在这个目录中创建一个文件
reverse.go
// Package stringutil contains utility functions for working with strings. //Reverse returns its argument string reversed run-wise left to right.
func Reverse(s string) string {
r := []rune(s)
for i , j := , len(r)-; i < len(r)/; i,j = i+, j- {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
- 测试 这个 pckage compiles with 命令
go build
:
$ go build github.com/user/stringutil
或者你在 这个目录下面,只需要
$ go build
即可。
go build
不会产生任何的文件。 我们需要使用go install
可以 将 package object 放置在 workspace下的 pkg目录下。
$ go install
- 为了确认
stringutil
已经建立(build),我们需要修改hello.go
文件。
package main
import (
"fmt"
"github.com/usr/stringutil"
) func main() {
fmt.Printf(stirngutil.Reverse("!oG, olleH"))
}
- 当 go tool 安装一个 package 或者 一个 binary(可执行二进制),它也会 installs whatever dependencies it has (安装它所依赖的文件). 所以当你 intall
hello
程序的时候
$ go install github.com/user/hell
stringutil
也会自动安装。
运行新版本的程序,你会看见如下结果:
$ hello
Hello, Go!
经过了上述的步骤,你的工作空间现在应该是下面的情况:
bin/
hello # command executalbe 可执行命令
pkg/
linux_amd64/ # this will reflect you OS and architecture
github.com/usre/
stringutil.a # package object
src/
github.com/user/
hello/
hello.go # command source
stringutil/
reverse.go # package source
可以看到, go install
将 stringutil.a
放置在 pkg/linux_amd64
的目录下, 这个目录 mirrors its source directory. 这是因为 以后 go tool 会找到 package object,并且会避免重新编译。 linux_amd64
是为了平台交叉编译,将会反映你的操作系统和计算机的体系结构。
Go command exectualbes are statically linked。(go command 执行是静态链接的) The package objects need not be present to run Go program.(pakcage object 在Go程序执行的时候是不需要的)。
Package names
在Go源文件中, 第一行语句一定是
package name
其中, name
is the package’s default name for imports. (All files in a package must use the same name
)
Go的惯例是, package name 是 import path 的最后一个元素: 比如,导入的包是 "crypto/rot13"
那么,它的 package name 就应该是 rot13
。 (其实,导入的包名 和 实际的 package name 并不必须要一致。 因为导入的 package 是这个包所在的目录,而这个包所在的目录并不一定和 package name是一致的。但是惯例二者是一样的)
可执行的命令 必须 使用 package main
包名 没有必要在 所有的包中(linked to a single binary)是唯一的,之哟啊 import path(它们的 full file name)是唯一的就可以了。
Testing
Go 有一个轻量级的测试框架: Tesing。 Testing 由 go test
命令 和 testing
包组成。
Testing 可以用作单元测试,也可以用来进行压力测试。
如何使用 Testing 写单元测试:
1. 创建一个文件, 这个文件以 _test.go
结束,比如: reverse_test.go
2. 这个文件包含测试函数: TestXXX ,其中XXX的起始字符不可是小写字母[a-z],测试函数签名为: func (t *testing.T)。
Testing 测试框架会 运行每个测试函数,一旦这个测试函数 调用了 failure function, 比如: t.Error
或者 t.Fail
,那么这个测试就表明失败了。
举例:
1. 向 stringutil
包中加入一个 测试文件。 也就是创建文件 $GOPATH/src/github.com/user/stringutil/reverse_test.go
,包含的代码如下
package stringutil import "testing" func TestReverse(t *testing.T) {
cases := []struct {
in, want string
} {
{"Hello, World", "dlrow, olleH"}
{"Hello, Go", "oG, olleH"}
{"", ""}
} for _, c := range case {
got := Reverse(c, in)
if got != c.want {
t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want)
}
}
}
- 运行测试用例
$ go test github.com/user/stringutil
ok github.com/user/stringutil .165s
As always,如果你在 package directory下面运行 go tool
,你就可以忽略 package path。
$ go test
ok github.com/user/stringutil .165s
如果你有疑问可以,运行go help test 并且看一下 testing package documentation 了解详情。
Remote packages (远程包安装)
go tool
可以用来自动的 fetch packages from remote repositories。(比如 Git 或者 Mercurial)。
举例, 在 Github github.com/golang/example
上有我们上文写过的代码。 如果你在 package’s import path中 包含这个 repository URL,那么 go get
命令将会 自动的 fetch build and install
这个包。(自动的获取,build,安装这个包)
$ go get github.com/golang/example/hello
$ $GOPATH/bin/hello
Hello, Go examples!
如果这个指定的 package 没有在 workspace中,那么 go get
命令将会 把 它放在 $GOPATH
指定的第一个 workspace中。(如果这个 package 已经存在了,那么 go get
将会忽略远程的 fetch,并且执行和 go install
一样的操作)
在 issuing go get
命令之后,现在的工作空间应该是这个样子:
bin/
hello # 可执行的命令
pkg/
linux_amd64/
github/golang/example/
stringutil.a # pakcage objects
github/user/
stringutil.a # package objects
src/
github.com/golang/example/
.git/ # git repository metadata
hello/
hello.go # command source
outyet/
main.go # command source
main_test.go # test source
stringuitl/
reverse.go # package source
reverse_test.go # test source
github.com/user/
hello/
hello.go # command source
stringutil/
reverse.go # package source
reverse_test.go # test source
Github中的 hello 命令 依赖于同一个代码仓库中的 stringutil。hello.go 文件中的 imports 需要使用同样的 import path convention(惯例),这样 go get
命令可以 定位并且安装依赖的 package.
import "github.com/golang/example/stringutil"
这个惯例很重要,大家一定要遵守。并且这个惯例 可以让你的包很轻松地被别人使用。
Go Wiki和godoc.org提供了一些列的 external Go progects.
本文来自:CSDN博客 感谢作者:xiaorenwuzyh 查看原文:Go 工作空间 深度解析
Go 工作空间 深度解析的更多相关文章
- [WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析
[WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析 标签: webkit内核JavaScriptCore 2015-03-26 23:26 2285 ...
- 第37课 深度解析QMap与QHash
1. QMap深度解析 (1)QMap是一个以升序键顺序存储键值对的数据结构 ①QMap原型为 class QMap<K, T>模板 ②QMap中的键值对根据Key进行了排序 ③QMap中 ...
- Deep Learning模型之:CNN卷积神经网络(一)深度解析CNN
http://m.blog.csdn.net/blog/wu010555688/24487301 本文整理了网上几位大牛的博客,详细地讲解了CNN的基础结构与核心思想,欢迎交流. [1]Deep le ...
- (转载)(收藏)OceanBase深度解析
一.OceanBase不需要高可靠服务器和高端存储 OceanBase是关系型数据库,包含内核+OceanBase云平台(OCP).与传统关系型数据库相比,最大的不同点, 是OceanBase是分布式 ...
- Kafka深度解析
本文转发自Jason’s Blog,原文链接 http://www.jasongj.com/2015/01/02/Kafka深度解析 背景介绍 Kafka简介 Kafka是一种分布式的,基于发布/订阅 ...
- java内存分配和String类型的深度解析
[尊重原创文章出自:http://my.oschina.net/xiaohui249/blog/170013] 摘要 从整体上介绍java内存的概念.构成以及分配机制,在此基础上深度解析java中的S ...
- Unity加载模块深度解析(Shader)
作者:张鑫链接:https://zhuanlan.zhihu.com/p/21949663来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 接上一篇 加载模块深度解析(二 ...
- Unity加载模块深度解析(网格篇)
在上一篇 加载模块深度解析(一)中,我们重点讨论了纹理资源的加载性能.这次,我们再来为你揭开其他主流资源的加载效率. 这是侑虎科技第53篇原创文章,欢迎转发分享,未经作者授权请勿转载.同时如果您有任何 ...
- 深度解析Java8 – AbstractQueuedSynchronizer的实现分析(上)
本文首发在infoQ :www.infoq.com/cn/articles/jdk1.8-abstractqueuedsynchronizer 前言: Java中的FutureTask作为可异步执行任 ...
随机推荐
- Spring对象依赖关系
Spring中,如何给对象的属性赋值? [DI, 依赖注入] 1) 通过构造函数 2) 通过set方法给属性注入值 3) p名称空间 4)自动装配(了解) 5) 注解 package loade ...
- Spring下使用Redis
在Spring中使用Redis使用使用两个依赖包jedis.jar.spring-data-redis.jar 一下是Maven项目pom.xml添加依赖 <!--jedis.jar --> ...
- Spark算子与RDD基本转换
map 将一个RDD中的每个数据项,通过map中的函数映射变为一个新的元素. 输入分区与输出分区一对一,即:有多少个输入分区,就有多少个输出分区. flatMap 属于Transformation算子 ...
- Kafka管理与监控——查看和重设消费者组位移
kafka 0.11.0.0版本丰富了kafka-consumer-groups脚本的功能,用户可以直接使用该脚本很方便地为已有的consumer group重新设置位移. 前提必须consumer ...
- 3.React中的setstate的几个现象
转载segfault 上面的一篇文章,https://segmentfault.com/a/1190000014498196 1.在同一个方法中多次setState是会被合并的,并且对相同属性的设置只 ...
- C#作业系统提示和故障排除
使用Unity C#作业系统时,请确保遵守以下内容: 不要从作业访问静态数据 从作业访问静态数据会绕过所有安全系统.如果您访问错误的数据,您可能会以意想不到的方式崩溃Unity.例如,访问MonoBe ...
- 图文详解 : 什么是版本控制?Eclipse配置SVN和IDEA配置GIT教程
前言 虽然在工作中, VCS已然配置妥当, 我们敲好的业务只需要Commit&push提交就好, 但是不妨碍我们了解什么是版本控制, 为什么要使用这类工具? ps.最近项目里的小伙伴想在自己家 ...
- pandas中截取一列字符串中每行字符串的一部分
import pandas as pd df = pd.DataFrame([[',1], [',2], [',3], [',4], [',5], [',6]],columns=['str','num ...
- Elasticsearch基础入门,详情可见官方文档
索引文档: 对于员工目录,我们将做如下操作: 每个员工索引一个文档,文档包含该员工的所有信息. 每个文档都将是 employee 类型 . 该类型位于 索引 megacorp 内. 该索引保存在我们的 ...
- 看kubelet的日志 + Kubeadm安装Kubernetes环境
1.通过journalctl看日志 journalctl -xeu kubelet > a参考:https://www.cnblogs.com/ericnie/p/7749588.html