使用Go语言进行高效的工程项目管理

发表时间: 2023-08-09 14:01

在实际的开发工作中, 直接调用编译器进行编译和链接的场景是少之又少, 因为在工程中不会简单到只有一个源代码文件, 且源文件之间会有相互的依赖关系。

如果这样一个文件一个文件逐步编译, 那不亚于一场灾难。 Go语言的设计者作为行业老将, 自然不会忽略这一点。

早期Go语言使用makefile作为临时方案, 到了Go1 发布时引入强大无比的Go命令行工具。

Go命令行工具的革命性之处在于彻底消除了工程文件的概念, 完全用目录结构和包名来推导工程结构和构建顺序。

针对只有一个源文件的情况讨论工程管理看起来会比较多余, 因为这可以直接用go run和go build搞定。

工作空间

依照规范, 工作空间(workspace)由src、bin、pkg三个目录组成。 通常需要将空间路径添加到GOPATH环境变量列表中, 以便相关工具能正常工作。

workspace/

---src/ 源码

---server/

--main.go

---service/

--user.go

---bin/ 可执行文件安装路径, 不会创建额外子目录

---server

---pkg/ 包安装路径, 按操作系统和平台隔离

---linux_amd64/

--service.s

在工作空间里, 包括子包在内的所有源码文件都保存在src目录下。至于bin、pkg两个目录, 其主要影响go install/get命令, 它们会将编译结果(可执行文件或静态库)安装到这两个目录下, 以实现增量编译。

Go代码必须放在工作区中。 工作区其实就是一个对应于特定工程的目录, 它应包含3个子目录:src目录、pkg目录和bin目录。

src目录: 用于以代码包的形式组织并保存Go源码文件。(比如: .go .c .h .s等)。

pkg目录: 用户存放经由go install命令构建安装后的代码包(包含Go库源码文件)的".a"归档文件。

bin目录: 与pkg目录类似, 在通过go install命令完成安装后, 保存由Go命令源码文件生成的可执行文件。

目录src用户包含所有的源代码, 是Go命令行工具一个强制的规则, 而pkg和bin则无需手动创建, 如果必要Go命令行工具在构建过程中自动创建这些目录。

特别要注意的是, 只有当环境变量GOPATH中只包括一个工作区的目录路径时, go install命令才会把命令源码安装到当前工作区的bin目录下。

若环境变量GOPATH中包括多个工作区的目录路径, 想这样执行go install命令就会失效, 此时必须设置环境变量GOBIN。

GOPATH设置

为了能够构建这个工程, 需要先把所需工程的根目录加入到环境变量GOPATH中。否则, 即使处于同一目录(工作区), 代码之间也无法通过绝对代码包路径完成调用。

在实际开发环境中, 工作目录往往有多个。这些工作目录的目录路径都需要添加至GOPATH。当有多个目录时, 请注意分隔符, 多个目录的时候Window是分号, Linux系统是冒号, 当有多个GOPATH时, 默认会将go get的内容

放到第一个目录下。

所有Go语言的程序都会组织成若干组文件, 每组文件被称为一个包。 这样每个包的代码都可以作为很小的单元, 被其他项目引用。

一个包的源代码保存在一个或多个以.go为文件后缀名的源文件中, 通常一个包所在目录路径的后缀是包的导入路径。

自定义包

对应一个较大的应用程序, 我们应该将它的功能性分隔成逻辑的单元, 分别在不同的包里实现。我们创建的自定义包最好放在GOPATH的src目录下(或者GOPATH src的某个子目录)。

在Go语言中, 代码包中的源码文件名可以是任意的。但是, 这些任意名称的源码文件都必须以包声明语句作为文件中第一行, 每个包都对应一个独立的名字空间:

packpage calc

包中成员以名称首字母大小写决定访问权限:

public: 首字母大写, 可被包外访问

private: 首字母小写, 仅包内成员可以访问

注意:同一个目录下不能定义不同的package, 一般而言, package定义的包名与目录名保持一致。

导入包

导入包需要使用关键字import, 它会告诉编译器你想引用该位置的包内的代码。包的路径可以是相对路径, 也可以是绝对路径。

//方法1

import "calc" //导入的是目录名(package定义的包名), 不包括文件名

import "fmt"

//方法2

import (

"calc" //导入的是目录名(package定义的包名), 不包括文件名

"fmt"

)

通过 package 关键字声明 Go 源文件所属的包:

// xx.go

package a

... ...

上述源码表示:文件 xx.go 是包 a 的一部分。

标准库中的包会在安装 Go 的位置找到。 Go 开发者创建的包会在 GOPATH 环境变量指定的目录里查找。GOPATH 指定的这些目录就是开发者的个人工作空间。

如果编译器查遍 GOPATH 也没有找到要导入的包, 那么在试图对程序执行 run 或者 build 的时候就会出错。

注意:如果导入包之后,未调用其中的函数或者类型将会报出编译错误。

实例:

import(

google.golang.org/protobuf/proto

)

对应的导入路径

/root/go/pkg/mod/google.golang.org/protobuf@v1.27.1/proto

main包

在 Go 语言里, 命名为 main 的包具有特殊的含义。 Go 语言的编译程序会试图把这种名字的包编译为二进制可执行文件。所有用 Go 语言编译的可执行程序都必须有一个名叫 main 的包。

一个可执行程序有且仅有一个 main 包, 当编译器发现某个包的名字为 main 时, 它一定也会发现名为 main()的函数, 否则不会创建可执行文件。

main()函数是程序的入口, 所以, 如果没有这个函数, 程序就没有办法开始执行。程序编译时, 会使用声明 main 包的代码所在的目录的目录名作为二进制可执行文件的文件名。

Go里面有两个保留的函数:init函数(能够应用于所有的package)和main函数(只能应用于package main)。这两个函数在定义时不能有任何的参数和返回值。

虽然一个package里面可以写任意多个init函数, 但这无论是对于可读性还是以后的可维护性来说, 我们都强烈建议用户在一个package中每个文件只写一个init函数。

Go程序会自动调用init()和main(), 所以你不需要在任何地方调用这两个函数。每个package中的init函数都是可选的, 但package main就必须包含一个main函数。

点操作

import (

//这个点操作的含义是这个包导入之后在你调用这个包的函数时,可以省略前缀的包名

. "fmt"

)

func main() {

Println("hello go") //调用的print.go文件的Println()方法, fmt为目录名

}

别名操作

在导入时, 可指定包成员访问方式, 比如对包重命名, 以避免同名冲突:

import (

io "fmt" //fmt改为为io

)

func main() {

io.Println("hello go") //通过io别名调用

}

_操作

有时, 用户可能需要导入一个包, 但是不需要引用这个包的标识符。在这种情况, 可以使用空白标识符_来重命名这个导入:

import (

_ "fmt"

)

func main() {

}

_操作其实是引入该包, 而不直接使用包里面的函数, 而是调用了该包里面的init函数。

同级目录:

1、分文件编程, 多个源文件, 必须放在src目录

2、设置GOPATH目录, 目录地址不包括src后缀

3、同一个目录, 包名必须一样

4、go env查看go相关的环境路径

5、同一个目录, 调用别的文件的函数, 直接调用即可, 无需包名调用

在同一包下(package 包名), 变量和函数的首字母小写的情况下, 可以直接调用

src

main.gopackage main //必须func main(){  test()}


src

test.go

package mainimport "fmt"func test(){		fmt.Println("this is a test func")}


测试方法:


go run *.go # window环境下测试有问题, 因为window系统不能识别"*"符号

this is a test func

或者

go build .

./src # window环境下不需要"./", 直接src.exe测试

LiteIDE工具测试: ctrl+R #编译和运行测试

不同目录:

1、不同目录, 包名不一样

2、调用不同包里面的函数, 格式:包名、函数名()

3、调用别的包的函数, 这个函数名字如果首字母是小写, 无法让别人调用, 要想别人能调用, 函数必须首字母大写

4、同一个目录下不能定义不同的package, 一般而言, package定义的包名与目录名保持一致。

src

main.go

package main


src/calc

calc.go

package calc


【实例】

main.go

package main //必须有个main包import("fmt""test" //加载的是package 定义的包名)func main(){    fmt.Println("main.go main() is called")    test.Test()}

test/test.go

package testimport "fmt"func init(){		fmt.Println("test.go init() is called")}func Test(){    fmt.Println("test.go test() is called")}

【实例】

main.go

package main //必须有个main包import(    "fmt"    "calc")func main(){    a := calc.Add(1, 2) //calc为 package 定义的包名, Add为 calc 包中定义的Add的方法    fmt.Println("a = ", a)}

calc/calc.go

package calcfunc Add(a, b int) int{    return a + b}func Minus(a, b int) int{    return a - b}func Multiply(a, b int) int{    return a * b}func Divide(a, b int) int{    return a / b}

go install 的使用

设置环境变量 GOBIN

D:\Go\study\src>setx GOBIN D:\Go\study\bin

cd D:\Go\study\src

go install

图形使用设置方法:

计算机->属性->高级系统设置->高级->环境变量->xxx的用户变量->新建->GOBIN D:\Go\study\bin