在实际的开发工作中, 直接调用编译器进行编译和链接的场景是少之又少, 因为在工程中不会简单到只有一个源代码文件, 且源文件之间会有相互的依赖关系。
如果这样一个文件一个文件逐步编译, 那不亚于一场灾难。 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