极客Go工程师零基础就业班
原创
©著作权归作者所有:来自51CTO博客作者mb61adc42101bee的原创作品,请联系作者获取转载授权,否则将追究法律责任
一. 基本结构,基本数据类型
1. 文件名、关键字与标识符
- Go 的源文件以
.go
为后缀名存储在计算机中,这些文件名均由小写字母组成,如 scanner.go
。如果文件名由多个部分组成,则使用下划线 _
对它们进行分隔,如 scanner_test.go
。文件名不包含空格或其他特殊字符 - 一个源文件可以包含任意多行的代码,Go 本身没有对源文件的大小进行限制。
- go语言是区分大小写的,标识符必须一字母或者下划线开头,以下是错误的标识符
- 1ab(以数字开头)
- case(Go 语言的关键字)
- a+b(运算符是不允许的)
_
本身就是一个特殊的标识符,被称为空白标识符。它可以像其他标识符那样用于变量的声明或赋值(任何类型都可以赋值给它),但任何赋给这个标识符的值都将被抛弃,因此这些值不能在后续的代码中使用,也不可以使用这个这个标识符作为变量对其它变量的进行赋值或运算。- 在编码过程中,你可能会遇到没有名称的变量、类型或方法。虽然这不是必须的,但有时候这样做可以极大地增强代码的灵活性,这些变量被统称为匿名变量。
- 程序的代码通过语句来实现结构化。每个语句不需要像 C 家族中的其它语言一样以分号
;
结尾,因为这些工作都将由 Go 编译器自动完成。如果你打算将多个语句写在同一行,它们则必须使用 ;
人为区分,但在实际开发中我们并不鼓励这种做法。
2. Go 程序的基本结构和要素
2.1 包的概念、导入与可见性
- 包是结构化代码的一种方式:每个程序都由包(通常简称为 pkg)的概念组成,可以使用自身的包或者从其它包中导入内容。
- 如同其它一些编程语言中的类库或命名空间的概念,每个 Go 文件都属于且仅属于一个包。一个包可以由许多以
.go
为扩展名的源文件组成,因此文件名和包名一般来说都是不相同的。 - 你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:
package main
。package main
表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main
的包。 - 一个应用程序可以包含不同的包,而且即使你只使用 main 包也不必把所有的代码都写在一个巨大的文件里:你可以用一些较小的文件,并且在每个文件非注释的第一行都使用
package main
来指明这些文件都属于 main 包。如果你打算编译包名不是为 main 的源文件,如 pack1
,编译后产生的对象文件将会是 pack1.a
而不是可执行程序。另外要注意的是,所有的包名都应该使用小写字母。 - 属于同一个包的源文件必须全部被一起编译,一个包即是编译时的一个单元,因此根据惯例,每个目录都只包含一个包。
- Go 中的包模型采用了显式依赖关系的机制来达到快速编译的目的,编译器会从后缀名为
.o
的对象文件(需要且只需要这个文件)中提取传递依赖类型的信息。如果 A.go
依赖 B.go
,而 B.go
又依赖 C.go
: - 这种机制对于编译大型的项目时可以显著地提升编译速度。
- 编译
C.go
, B.go
, 然后是 A.go
. - 为了编译
A.go
, 编译器读取的是 B.o
而不是 C.o
.
- 一个 Go 程序是通过
import
关键字将一组包链接在一起。 - 如果需要多个包,它们可以被分别导入:
import "fmt"
import "os"
或:
import "fmt"; import "os"
但是还有更短且更优雅的方法(被称为因式分解关键字,该方法同样适用于 const、var 和 type 的声明或定义):
import (
"fmt"
"os"
)
它甚至还可以更短的形式,但使用 gofmt 后将会被强制换行:
import ("fmt"; "os")
- 如果包名不是以
.
或 /
开头,如 "fmt"
或者 "container/list"
,则 Go 会在全局文件进行查找;如果包名以 ./
开头,则 Go 会在相对目录中查找;如果包名以 /
开头(在 Windows 下也可以这样使用),则会在系统的绝对路径中查找。 - 除了符号
_
,包中所有代码对象的标识符必须是唯一的,以避免名称冲突。但是相同的标识符可以在不同的包中使用,因为可以使用包名来区分它们。 - 当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 private )。
- 假设在包 pack1 中我们有一个变量或函数叫做 Thing(以 T 开头,所以它能够被导出),那么在当前包中导入 pack1 包,Thing 就可以像面向对象语言那样使用点标记来调用:
pack1.Thing
(pack1 在这里是不可以省略的)。 - 因此包也可以作为命名空间使用,帮助避免命名冲突(名称冲突):两个包中的同名变量的区别在于他们的包名,例如
pack1.Thing
和 pack2.Thing
。 - 你可以通过使用包的别名来解决包名之间的名称冲突,或者说根据你的个人喜好对包名进行重新设置,如:
import fm "fmt"
。下面的代码展示了如何使用包的别名:
示例
package main
import fm "fmt" // alias3
func main() {
fm.Println("hello, world")
}
- 如果你导入了一个包却没有使用它,则会在构建程序时引发错误,如
imported and not used: os
,这正是遵循了 Go 的格言:“没有不必要的代码!“。 - 这是定义一个函数最简单的格式:
func functionName()
你可以在括号 ()
中写入 0 个或多个函数的参数(使用逗号 ,
分隔),每个参数的名称后面必须紧跟着该参数的类型