本文会演示简单的Go软件包的开发过程,并介绍了 go命令行工具,这是我们获取,构建和安装Go软件包和命令的标准方法。

go工具要求你以特定方式组织代码。我们会介绍Go安装启动和运行的最简单方法,一定要仔细阅读啊。

组织代码结构

概要

  • Go 程序员一般会将他们的源代码存放在一个工作区中(多个项目放在一个工作区)

  • 工作区中包含许多由 git 管理的代码仓库(也可以是其他版本控制工具管理的)

  • 每个代码仓库包含一个或者多个 Go package

  • 每个 package 由单一目录下的一个或多个Go 源码文件组成

  • package 的目录路径决定了其导入路径

与其他编程语言不同的是,在其他编程语言里每个项目都有自己的工作区,并且工作区都与版本控制系统紧密相关。

工作区

工作区是一个目录层级,这个目录层级在顶层有两个目录:

  1. src 目录,存放源代码文件。

  2. bin 目录,存放可执行二进制文件。

go命令工具会把 src中的Go 文件构建生成二进制文件放在 bin目录中。

src子目录通常包含用 git 管理的多个代码仓库,他们对应一个或多个Go 包的开发源码。

一个典型的工作区中会包含多个源码仓库,对应多个可执行命令源码和包源码。大多数 Go 程序员会把他们的Go 源码和所有依赖的包都放在单一的工作区中。

下面的例子可以让你更好的了解Go 的工作区大概的样子:

bin/

hello # 可执行命令文件

outyet # 可执行命令文件

src/

github.com/golang/example/

.git/

hello/

hello.go # 命令文件源码

outyet/

main.go # 命令文件源码

main_test.go # 测试文件

stringutil/

reverse.go # package源码

reverse_test.go # 测试文件

golang.org/x/image/

.git/

bmp/

reader.go # package 源码

writer.go # package 源码

......

上面的目录树展示了工作区中的两个代码仓库(example 和 image)。example 仓库中包含两个命令hello 和 outyet(hello 和 outyet 目录中存放的就是两个命令的源码)一个被用作库的 package - stirngutil 。image仓库中包含一个 bmp包。

注意:不能使用符号链接(软链 ln -s)将文件链接到工作区中。

执行命令和库是从不同类的源码包构建出来的,这个之后的部分会进行说明。

GOPATH 环境变量

GOPATH环境变量指定工作区的位置。它缺省为用户目录中名为go的目录,因此在Linux上为 $HOME/go,在Windows上通常为 C:\Users\YourName\Go

如果想在其他位置放置工作区,则需要将 GOPATH设置为该目录的路径。请注意,GOPATH不得与GO安装路径相同。

命令 go env GOPATH打印当前有效的 GOPATH;如果环境变量未设置,它将打印默认位置。为方便起见,可以请将工作区的 bin子目录添加到系统环境变量 $PATH

$ export PATH=$PATH:$(go env GOPATH)/bin

同时也把 GOPATH设置成系统的环境变量:

$ export GOPATH=$(go env GOPATH)

包的导入路径

一个导入路径是用来唯一标识包的字符串,包的导入路径和他在工作区中的位置相对应。标准库中的包具有较短的导入路径,如“fmt”和“net/http”。对于您自己的软件包,你必须选择一个不太可能与将来添加到标准库或其他外部库中的内容冲突的基本路径。

如果你将代码保存在某个源代码库中,那么应该使用该源代码库的根目录作为你的基本路径。例如,如果你在github.com上有一个GitHub帐户user,你创建的仓库都会以 github.com/user 为前缀,那么 github.com/user这应该是你的基本路径。

请注意,在构建代码之前,你不需要将代码发布到远程存储库。就像有一天会发布代码一样来组织代码,这是一个好习惯。实际上,您可以选择任意路径名,只要它是唯一的。

我们将使用 github.com/user作为基本路径。在工作区内创建一个保存源代码的目录:

$ mkdir -p $GOPATH/src/github.com/user

你的第一个Go程序

要编译并运行一个简单的程序,首先选择一个软件包路径(我们将使用github.com/user/hello),并在您的工作区内创建一个相应的软件包目录:

$ mkdir $GOPATH/src/github.com/user/hello

接下来,在该目录中创建一个名为hello.go的文件,添加以下代码:

package main

import "fmt"

func main() {

fmt.Println("Hello, world.")

}

现在,你可以使用go工具构建和安装该程序了:

$ go install github.com/user/hello

你可以从系统上的任何位置运行此命令。go命令工具通过在 GOPATH指定的工作区内查找 github.com/user/hello包来查找源代码。如果从软件包目录运行 goInstall,可以省略软件包路径:

$ cd $GOPATH/src/github.com/user/hello

$ go install

go install构建hello命令,生成一个可执行的二进制文件。然后,它将该二进制文件作为hello(在Windows下为hello.exe)安装到工作区的bin目录中,hello 可执行命令的位置为 $GOPATH/bin/hello

Go工具仅在发生错误时打印输出,因此如果这些命令没有产生输出,则代表它们已成功执行。

现在,你可以通过在命令行中键入程序的完整路径来运行该程序:

$ $GOPATH/bin/hello

Hello, world.

由于您已将 $GOPATH/bin添加到路径中,因此只需键入二进制文件的名字:

$ hello

Hello, world.

你的第一个 library

让我们编写一个库并在上面写的hello程序中使用它。

同样,第一步是选择软件包路径(我们将使用github.com/user/stringutil)并创建软件包目录:

$ mkdir $GOPATH/src/github.com/user/stringutil

接下来在目录中创建 reverse.go文件并添加如下代码:

// stringutil包 存放关于字符串的工具函数

package stringutil

// Reverse 将参数中的字符串反转后的字符串

func Reverse(s string) string {

r := []rune(s)

for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {

r[i], r[j] = r[j], r[i]

}

return string(r)

}

现在,使用 go build测试软件包的编译情况:

$ go build github.com/user/stringutil

go build不会产生输出文件。相反,它将编译后的包保存在本地构建缓存中。

在确认 stringutil包构建可以正确之后,修改原始的 hello.go(位于$GOPATH/src/github.com/user/hello中)以使用它:

package main

import (

"fmt"

"github.com/user/stringutil"

)

func main() {

fmt.Println(stringutil.Reverse("!oG ,olleH"))

}

再次编译安装 hello 程序后运行他,可以看到输出中的字符串已经被反转了。

$ hello

Hello, Go!

经过上面几步后你的工作区现在应该看起来像下面这样:

bin/

hello

src/

github.com/user/

hello/

hello.go

stringutil/

reverse.go

包名

go 源码文件中的第一行语句必须是:

package name

其中,name是用于导入的包的默认名称。(包中的所有文件必须使用相同的名称)

go的惯例是包名是导入路径的最后一个元素:作为“crypto/rot13”导入的包它的包名为 rot13

生成可执行命令的源码文件必须以 main作为包名。

go 中不要求链接到单个二进制文件的所有包的包名都是唯一的,只要求导入路径(它们的完整文件名)是唯一的。

测试

go有一个由go测试命令和测试包组成的轻量级测试框架。你可以通过创建一个名字以 _test.go结尾的文件来编写测试,该文件包含名为TestXXX的函数,签名函数为 func(t*testing.T)。测试框架运行每个这样的函数;如果函数调用失败函数,如t.Error或t.Fail,则认为测试失败。

通过创建包含以下go代码的文件 $GOPATH/src/github.com/user/stringutil/reverse_test.go,将测试添加到 strangutil包。

package stringutil

import "testing"

func TestReverse(t *testing.T) {

cases := []struct {

in, want string

}{

{"Hello, world", "dlrow ,olleH"},

{"Hello, 世界", "界世 ,olleH"},

{"", ""},

}

for _, c := range cases {

got := Reverse(c.in)

if got != c.want {

t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want)

}

}

}

然后使用 go test运行测试

$ go test github.com/user/stringutil

ok github.com/user/stringutil 0.165s

导入路径可以描述如何从版本控制系统(如Git)获取包源代码。Go工具使用此属性自动从远程仓库中获取包。例如,本文档中描述的示例也保存在GitHub 以github.com/golang/example托管的Git存储库中。如果将代码仓库的URL包含在软件包的导入路径中,go将会使用go get`自动获取、构建和安装它:

$ go get github.com/golang/example/hello

$ $GOPATH/bin/hello

Hello, Go examples!

如果工作区中没有指定的包, goget将把它放在 $GOPATH指定的工作区中。(如果软件包已经存在, goget将跳过远程获取,其行为变得与 go install相同。)。

发出上述 goget命令后,工作区目录树现在应该如下所示:

bin/

hello

src/

github.com/golang/example/

.git/

hello/

hello.go

stringutil/

reverse.go

reverse_test.go

github.com/user/

hello/

hello.go

stringutil/

reverse.go

reverse_test.go

托管在GitHub上的hello命令依赖于同一仓库中的 stringutil包。hello.go文件中的导入使用相同的导入路径约定,因此 goget命令也能够定位和安装依赖包。

import "github.com/golang/example/stringutil"

What's Next

  • 《Go语言之旅》https://tour.go-zh.org/list 了解 Go 语言的基础语法

  • 《Go 入门指南》https://learnku.com/docs/the-way-to-go 通过了200 多个完整的代码示例和书中的解释说明来对所有涉及到的概念和技巧进行彻底的讲解。

  • 《Go语言程序设计》https://yar999.gitbooks.io/gopl-zh/content/ 通过学习这本书会对 Go 有更全面的认识,强化自己的Go语言底层基础知识。

  • 《Effective Go 中文版》https://learnku.com/docs/effective-go/2020 提供编写清晰高效、地道的 Go 代码的技巧。

推荐阅读

  • 我是如何学习 Go 语言的

  • 我的 Go 语言学习之路


喜欢本文的朋友,欢迎关注“Go语言中文网”:

Go语言中文网启用微信学习交流群,欢迎加微信:274768166

go get 的不再src目录中_如何正确的开始用Go编程相关推荐

  1. go get 的不再src目录中_GO语言基础进阶教程:包的使用

    Go语言使用包(package)这种语法元素来组织源码,所有语法可见性均定义在package这个级别,与Java .python等语言相比,这算不上什么创新,但与C传统的include相比,则是显得& ...

  2. go get 的不再src目录中_Go 每日一库之 sqlc:根据 sql 生成代码

    简介 在 Go 语言中编写数据库操作代码真的非常痛苦!database/sql标准库提供的都是比较底层的接口.我们需要编写大量重复的代码.大量的模板代码不仅写起来烦,而且还容易出错.有时候字段类型修改 ...

  3. 将解决方案和项目放在同一目录中_借助CADENAS 3D电子目录,巴鲁夫使用CAE数据扩展其产品目录...

    巴鲁夫作为一家中型企业,1921年成立于毗邻斯图加特市的诺伊豪森,80年代初期直至后来很长的一段时间内,巴鲁夫是巴西第一家及唯一一家从事自主生产的传感器制造商.如今巴鲁夫不再仅仅位于诺伊豪森,而是遍布 ...

  4. 将解决方案和项目放在同一目录中_借助卡第那思3D电子目录,巴鲁夫使用CAE数据扩展其产品目录...

    巴鲁夫作为一家中型企业,1921年成立于毗邻斯图加特市的诺伊豪森,80年代初期直至后来很长的一段时间内,巴鲁夫是巴西第一家及唯一一家从事自主生产的传感器制造商.如今巴鲁夫不再仅仅位于诺伊豪森,而是遍布 ...

  5. 属于mysql安装目录中_下面选项中,属于 MySQL 安装目录中包含的文件是()_Flash 二维动画设计与制作答案_学小易找答案...

    [单选题]在下列经济行为中,属于货币执行流通手段职能的是( ) [单选题]28 .资本主义生产过程的二重性是指资本主义生产过程是( ) [单选题]能够证明其服务产品特征和价值的凭证,是顾客可以通过五官 ...

  6. 主程序与子程序不在同一程序模块中_数控车床子程序M98、M99编程实例!

    把程序中某些固定顺序和重复出现的程序单独抽出来,按一定格式编成一个程序供调用,这个程序就是常说的子程序,这样可以简化主程序的编制.子程序可以被主程序调用,同时子程序也可以调用另一个子程序.这样可以简化 ...

  7. 如何忽略Git中目录中的文件?

    本文翻译自:How do I ignore files in a directory in Git? What is the proper syntax for the .gitignore file ...

  8. java实现递归下降分析_使用递归实现检查未知层级目录中的文件-Java实用技能

    现在有这样一个需求,给你一个目录,需要你在此目录中查找全部名字中包含指定字符的文件. 这题的主要难点在于:目录中可能包含子目录,子目录中又会包含子目录.而我们事先没办法确定子目录到底有多少层!这时候就 ...

  9. python遍历目录树_在Python中遍历目录树的速度要快得多?

    假设给定目录树的大小是合理的:比如Twisted或Python这样的开源项目,遍历和迭代该目录中所有文件/目录的绝对路径的最快方式是什么? 我想在Python中完成这项工作.os.path.walk很 ...

最新文章

  1. 谭浩强课后题之----求最大公约数和最小公倍数
  2. 双目摄像头 三维坐标 python_时间编码单像素三维成像:挑战三维成像的速度极限...
  3. 第四次上课 PPT作业
  4. 解决yarn全局安装模块后但仍提示无法找到命令的问题
  5. 2018年湘潭大学程序设计竞赛 G又见斐波那契
  6. leetcode双指针(python与c++)
  7. mysql infile local,MySQL:启用LOAD DATA LOCAL INFILE
  8. Tricks(三十三)—— 自定义 zipWithIndex
  9. 计算机组成与设计RISC-V版笔记
  10. otdr测试曲线图软件通用,OTDR常见测试曲线
  11. vbs格式编程教程提高
  12. c语言pow函数原型_c语言中pow函数的用法是什么?_后端开发
  13. 关于ansys19.0安装问题
  14. PHP 出现 The requested URL was not found on this server 怎么办?
  15. tf.trian.match_filenames_once
  16. 国内虚拟主机与香港云主机的优劣势
  17. 【win10蓝屏】记录一下,随机蓝屏,开机蓝屏,使用中蓝屏的经历
  18. kettle的调度监控平台
  19. C语言编程练习 念数字
  20. Python面向对象之:三大特性:继承,封装,多态以及类的约束

热门文章

  1. php软件开发--sphinx索引静态化及伪静态
  2. Bootstrap 调用插件
  3. 堆、队列、栈、链表对比
  4. Git笔记(10) 别名
  5. matlab中基于十字形窗口的滤波算法,#215;字形滤波窗口在Matlab自适应中值滤波算法中的应用 - 21ic中国电子网...
  6. php中http有哪些状态码,http状态码是什么意思?http常用状态码有哪些
  7. 2019-05-22 防范ASP木马;如何防止注入攻击;
  8. Hive的数据库和表
  9. python之旅-day2(较基础阶段)
  10. angularjs directive2