Go语言学习 二 概念篇:Go代码的组织结构及基本概念介绍

本文介绍了Go语言代码的组织结构,包括工作空间、GOPATH环境变量、导入路径和内部目录的概念。工作空间包含src、pkg和bin目录,每个仓库可以有多个包,包由导入路径决定。GOPATH指定了代码的位置,而模块的引入改变了GOPATH的作用。内部目录的代码只能被其父目录树中的代码导入,供应商目录用于本地依赖的管理。理解这些基础概念对于Go语言的学习至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文最初发表在我的个人博客,欢迎查看原文:
blog.favorstack.io/golang


概览

  • Go程序员通常会将所有Go代码保存在一个工作区中。
  • 工作空间可以包含多个版本控制仓库(比如,Git仓库)。
  • 每个仓库可以包含一个或多个包。
  • 每个包由一个目录中的一个或多个Go源文件组成。
  • 包目录的的路径决定了其导入路径。

使用过Eclipse的同学可能觉得这跟Eclipse的工作空间有点像,但是跟Idea反差就很大。

工作空间(workspace)

Go的工作空间就是一个目录层次结构,其根目录下主要有以下几个子目录:

  • src 包含Go的源代码文件
  • bin 包含可执行命令文件
  • pkg 包含安装包的对象,按系统架构区分子目录

src 子目录通常包含多个版本控制仓库(比如git或hg),来追踪一个或多个源代码包的开发。该目录同样定义了导入路径或可执行命令的名称。

pkg 保存安装包的对象,在pkg下,每个目标操作系统和系统架构对都有自己的子目录(pkg/GOOS_GOARCH)。

假设工作空间路径为MyDIR,在MyDIR/src/foo/bar中包含源代码的包,可以导入为"foo/bar",并将其编译形式安装到"MyDIR/pkg/GOOS_GOARCH/foo/bar.a"

bin 目录保存已编译好的命令(可执行文件)。每个命令(可执行文件)都以其源目录命名,但仅以最后一个元素(包)命名,而不是整个路径。也就是说,源代码在MyDIR/src/foo/hello下的命令,会被安装到MyDIR/bin/hello,而不是MyDIR/bin/foo/hello。去掉了"foo/"前缀,以便可以将MyDIR/bin添加到PATH来获取已安装的命令。如果设置了GOBIN环境变量,则命令将安装到它命名的目录,而不是MyDIR/bin。注意,GOBIN必须是绝对路径。

go tool构建二进制文件并将其默认安装到bin目录。

下面是一个Go工作空间常见的例子:

bin/
    hello                          # command executable
    outyet                         # command executable
src/
    github.com/favorstack/go-example/
        .git/                      # Git repository metadata
        hello/
	         hello.go               # command source
        outyet/
      	    main.go                # command source
      	    main_test.go           # test source
        stringutil/
      	    reverse.go             # package source
      	    reverse_test.go        # test source
    favorstack.io/x/image/
        .git/                      # Git repository metadata
        bmp/
      	    reader.go              # package source
      	    writer.go              # package source
    ... (many more repositories and packages omitted) ...

上面的工作空间树展示了2个仓库go-exampleimage

典型的工作空间包含多个源代码仓库,每个仓库又包含多个包和命令。大多数程序员习惯将所有的Go源代码和依赖放到一个单独的工作空间。

需要注意的的是,不能将文件用符号链接的形式连接到工作空间,即,不要在工作空间使用文件(夹)快捷方式。

GOPATH 环境变量

GOPATH环境变量指定了工作空间的位置,用于查找go代码,解析import语句。默认指向家目录下的go目录。如Unix下的$HOME/go,或者Windows下的%USERPROFILE%\go(通常是 C:\Users\YourUserName\go)。该变量可以指定多个目录,在Unix下值以冒号:分隔;在Win下以分号;分隔。Go搜索GOPATH中列出的每一个目录以查找源代码,但新包通常会下载安装到第一个列出的目录。

GOPATH下的每一个目录都必须有规定的目录结构,如 工作空间 一节所述。

如果你不想使用默认的工作空间,就需要设置GOPATH环境变量,另外,该变量一定不能与Go的安装路径相同。

命令go env GOPATH会打印出当前有效的GOPATH路径,如果没有设置过该变量,就会打印出默认的路径。

自定义工作空间GOPATH
Bash:
编辑 ~/.bash_profile 添加如下内容:

# 这里可以将$HOME/go替换为你想要的路径
export GOPATH=$HOME/go

保存并退出编辑器,然后刷新 ~/.bash_profile:

$ source ~/.bash_profile

方便起见,将工作空间的bin目录加入到环境变量:

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

更多其他环境的设置:Set GOPATH.

注:本文及后续所有内容中,都使用默认的路径。以下表示的路径是等价的:

  • go env GOPATH
  • $GOPATH
  • $HOME/go
  • ~/go

GOPATH 和 模块

使用模块时,GOPATH不再用于解析导入。但是,它仍然用于存储下载的源代码(在GOPATH/pkg/mod中)和编译的命令(在GOPATH/bin中)。

内部目录

名为“internal”的目录中的代码,只能由以internal的父目录为根目录的目录树中的代码导入。如下面这个目录结构:

/home/user/go/
        src/
            crash/
                bang/              (go code in package bang)
                    b.go
            foo/                   (go code in package foo)
                f.go
                bar/               (go code in package bar)
                    x.go
                internal/
                    baz/           (go code in package baz)
                        z.go
                quux/              (go code in package main)
                    y.go

z.go中的代码可以导入为"foo/internal/baz",但是该import语句只能出现在以foo为根的子树中的源文件中。源文件foo/f.go, foo/bar/x.go, 和foo/quux/y.go 都可以导入 "foo/internal/baz",但是源文件crash/bang/b.go不可以。

供应商目录

Go 1.6开始支持使用外部依赖项的本地副本来满足这些依赖项的导入,通常称为vendoring。
vendor目录下的代码只能由以vendor的父目录为根目录的目录树中的代码导入,并且只能使用省略前缀和vendor元素的导入路径。

看下面这个例子:

/home/user/go/
        src/
            crash/
                bang/              (go code in package bang)
                    b.go
            foo/                   (go code in package foo)
                f.go
                bar/               (go code in package bar)
                    x.go
                vendor/
                    crash/
                        bang/      (go code in package bang)
                            b.go
                    baz/           (go code in package baz)
                        z.go
                quux/              (go code in package main)
                    y.go

这是上一节中的示例,但将internal目录重命名为vendor并添加了新的foo/vendor/crash/bang目录。vendor目录与internal具有相同的可见性规则,但区别在于z.go中的代码导入为"baz",而不是"foo/vendor/baz",即省略了从vendor往前的前缀。

源码树中较深层次的vendor目录下的代码会影响较高层次目录中的代码。在以foo为根的子树中,"crash/bang"的导入解析为"foo/vendor/crash/bang",而不是顶层的"crash/bang"

vendor目录中的代码不受导入路径检查的限制(请参阅go help importpath)。

go get检出或更新git仓库时,它现在也会更新子模块。

vendor目录不会影响第一次通过go get检出的新仓库的位置:这些仓库始终位于主GOPATH中,而不是位于供应商子树中。

导入路径

导入路径是唯一标识包的一个字符串。包的导入路径对应于其在工作空间内或远程存储库中的位置。

标准库中的包具有简短的导入路径,如"fmt""net/http"。对于我们自己的包,你必须选择一个不太可能与未来标准库的扩充或其他外部库冲突的基路径。

这一点与Java类似,自定义包不允许使用与JDK中相同的包名,但也仅此而已。

如果你将代码保存在某个源代码库中,使用该源代码库的根路径作为基路径是个不错的选择。比如,如果你的github地址是github.com/user,那么就可以把这个路径作为你的基路径。

需要注意的是,在构建代码之前,无需将代码发布到远程仓库库。组织代码只是一个好习惯,说不定哪天你会发布它呢。实际上,你可以选择任意路径名称,只要它跟标准库和更大的Go生态系统相比是唯一的。

了解了这些概念后,下一章我们重新看一下helloworld程序的例子。

参考

  1. 命令行帮助:go help gopath
  2. https://golang.org/doc/code.html
  3. https://golang.org/s/go14internal
  4. https://golang.org/s/go15vendor
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值