[TOC]
1.第一个Go程序
几乎所有的程序开始都是以Hello World小例子作为开始。我们也不面熟(或者说尊重传统),下面我们从一个简单Go语言版本的Hello World来初窥Go这门新语言的模样。
hello.go
|
|
代码解读:
每个Go源码文件的开头都是以一个package开头,表示该Go代码所属的包。包是Go中最基本的分发单位,也会工程管理中依赖关系的体现。要生成可执行文件,必须建立一个名字为main的包,并且在该包中包含一个叫main()的函数(该函数为Go可执行程序的起点,也只能含有一个)。
main()函数定义为不能带参数、返回值。命令行的参数保存在os包中的os.Args中,命令行的参数解析可以通过flag包解析,在后面章节中我们回看到如何使用flag包。
在包的声明后会含有一系列的import语句,用于导入该程序所依赖的包。(有一点需要注意:⚠️ 在源码文件中不能包含没有使用的包,否则会编译错误)
所有的Go函数都是以func关键字开头一个常规的函数包涵一下格式。
|
|
在Go的函数中支持多个函数返回值,比如上面的例子中返回了retVal和error。但是并不是所有的返回值都需要赋值,如果函数返回值没有被明确的赋值都会被设置为对应的类型的零值,比如retVal被设置为0.0,err被设置为nil。
Go中的注释
Go的注释和C++保持一致,同时支持一下两种方式:
|
|
⚠️
在Go源码文件中不能包含没有使用的包,否则会编译错误。
在Go源码文件中不能使用分号。
同时在含有括号的语句中,左括号({)不能另起一行。syntax error: unexpected semicolon or newline before {
代码的编译与执行
12$ go run hello.go #直接执行Hello, world. 你好,世界!使用如上命令,会将编译、链接和运行3个步骤合并为一步。运行完成后在当前目录下也看不到中间文件和最终的可执行文件。如果需要生成编译结果,不需要自动执行,可以使用build命令:
123$ go build hello.go #编译$ ./helloHello, world. 你好,世界!
工程管理
在实际的开发工作中,直接调用编译器进行编译和链接的场景是少而又少,因为在工程中不会简单到只有一个源代码文件,且源文件之间会有相互的依赖关系。如果这样一个文件一个文件逐步编译,那不亚于一场灾难。Go语言的设计者作为行业老将,自然不会忽略这一点。早期Go语言使用makefile作为临时方案,到了Go 1发布时引入了强大无比的Go命令行工具。
Go命令行工具的革命性之处在于彻底消除了工程文件的概念,完全用目录结构和包名来推导工程结构和构建顺序。针对只有一个源文件的情况讨论工程管理看起来会比较多余,因为这可以直接用go run和go build搞定。下面我们将用一个更接近现实的虚拟项目来展示Go语言的基本工程管理方法。
假设有这样一个场景:我们需要开发一个基于命令行的计算器程序。下面为此程序的基本用法:
|
|
我们假设这个工程被分割为两个部分:
可执行程序,名为calc,内部只包含一个calc.go文件;
算法库,名为simplemath,每个command对应于一个同名的go文件,比如add.go。
|
|
在上面的结构里,带尖括号的名字表示其为目录。xxx_test.go表示的是一个对于xxx.go的单元测试,这也是Go工程里的命名规则。
为了让读者能够动手实践,这里我们会列出所有的源代码并以注释的方式解释关键内容,需要注意的是,本示例主要用于示范工程管理,并不保证代码达到产品级质量。
cal.go
|
|
add.go
|
|
add_test.go
|
|
sqrt.go
|
|
sort_test.go
|
|
为了能够构建这个工程,需要先把这个工程的根目录加入到环境变量GOPATH中。
执行测试go test simplemath
生成可执行文件go install calc.go
进入bin ./calc add 1 2