2.基础语法
2.基础语法
2.1 关键字
每一种语言都有自己特定的关键字(也称保留字),这些关键字会在该语言中被赋予特定意义。因此这些关键字不允许做为标识符,Go 语言设置了 25 个关键字。如下所示:

可以在 Go 安装目录中
doc->go_spec.html->Keywords查看。
各个关键字的主要含义如下所示:
| 关键字 | 功能 |
|---|---|
| break | 中断整个循环 |
| default | 设置默认值,常与 switch、select 结合使用 |
| func | 定义函数或方法 |
| interface | 定义接口 |
| select | 选择结构,常与 case、default 结合使用 |
| case | 选择结构,常与 switch、select 结合使用 |
| defer | 延时执行语句 |
| go | 执行并发 |
| map | 定义 map 对象 |
| struct | 定义结构体 |
| chan | 定义通道 |
| else | 判断语句,常与 if 结合使用 |
| goto | 跳转语句 |
| package | 定义一个包名 |
| switch | 选择语句,常与 case、default 结合使用 |
| const | 定义常量 |
| fallthrough | 常用于 switch-case 语句中,当 case 语句匹配成功时,仍强制匹配其他的 case 语句 |
| if | 判断语句,常与 else 一起使用 |
| range | 常用于迭代切片、管道、map 的元素 |
| type | 定义自定义数据类型 |
| continue | 中断本次循环,继续下一次循环 |
| for | 循环语句 |
| import | 导入包 |
| return | 定义函数或方法的返回值 |
| var | 定义变量 |
2.2 标识符
在计算机编程语言中,标识符是用户编程时使用的名字,主要用于给变量、常量、函数、语句块等进行命名。
2.2.1 命名规范
每个语言都有自己的标识符命名规则,Go 语言的命名规则如下所示:
- 标识符由
字母、下划线和数字组成,但第一个字符不允许为数字 - 标识符
不允许使用Go语言的关键字 - 标识符不允许使用
空格、$、@、%等特殊字符 - 标识符严格
区分大小写
以下为合法的标识符
Surpass
name
first_name
middleName
_last_name
以下为不合法的标识符
for // 使用了Go关键字
$Surpass //使用了特殊字符
28age // 第一个字符为数字
Go 语言标识符命名规则比较简单,但为了使用标识符更具有可读性和代码具有可维护性,还需要遵循以下规范:
- 标识符尽量
简洁且具有意义,尽可能做到见名知意 - 如果一个单词无法表示一个变量,建议使用
驼峰命名法进行命名
驼峰命名有以下两种方式:
小驼峰命名法:仅第一个单词首字母小写,后续单词首字母大写,例如:myName、myAge大驼峰命名法:每个单词首字母大写,例如:MyName、MyAge
2.2.2 标识符类型
在 Go 语言中标识符被分成了 4 种类型空白标识符、预声明标识符、导出标识符、唯一标识符,
可以查阅 SDK 中 doc 中 go_spec.html 相应介绍
2.2.2.1 空白标识符
空白标识符通常使用下划线(_)表示,又称为匿名占位符。当一个变量存在但不想被使用时,就可以使用空白标识符进行表示,而程序也不会提示错误。主要使用场景如下所示:
- 1.导入某个包,只执行包里面的 init()函数,而不调用包的任何变量或函数,如下所示:
package main
import (
"fmt"
_ "net/http/pprof"
)
func main() {
fmt.Print("Test bland identifier by Surpassme")
}
- 2.当函数有多个返回值,但却只想使用其中某一个返回值,不使用的返回值就可以使用空白标识符,如下所示:
package main
import (
"fmt"
)
func personInfo(name string,age int)(string,int){
return name,age
}
func main() {
name:="Surpass"
age:=28
myName,_:=personInfo(name,age)
fmt.Println("my name is:",myName)
}
- 3.类型断言,判断某个类型是否实现了接口,否则则会编译出错,如下所示:
package main
import (
"fmt"
)
// 定义接口
type PersonAction interface {
introduce() string
}
// 定义结构体
type PersonInfo struct {
name string
}
func (p PersonInfo) introduce() string {
return fmt.Sprintf("name is %s", p.name)
}
func main() {
// 如果PersonInfo没有实现PersonAction,则会出错报错
// 接口可以看成是一种约束
var _ PersonAction = PersonInfo{"Surpass"}
}
2.2.2.2 预声明标识符
预声明标识符主要指 Go 语言基础数据类型和内置方法,这些预声明标识符不可以当作标识符使用。常见的预声明标识符如下所示:
| 预声明标识符 | 功能 |
|---|---|
| bool | 布尔类型 |
| byte | 字符类型,等同于 int8,常用于处理 ASCII 字符 |
| error | 异常类型 |
| float32 | 浮点类型 |
| float64 | 浮点类型 |
| int | 整型,大小与操作系统位数相关 |
| int8 | 整型,范围-128~127 |
| int16 | 整型,范围-32768~32767 |
| int32 | 整型,范围--2^31 ~ 2^31-1 |
| int64 | 整型,范围-2^63 ~ 2^63-1 |
| rune | 字符类型,等同于 int32,常用于处理 unicode 或 utf-8 字符 |
| string | 字符串类型 |
| uint | 无符号整型,大小大小与操作系统位数相关 |
| uint8 | 无符号整型,范围为 0~2^8-1 |
| uint16 | 无符号整型,范围为 0~2^16-1 |
| uint32 | 无符号整型,范围为 0~2^32-1 |
| uint64 | 无符号整型,范围为 0~2^64-1 |
| iota | 常量计数器,仅能在常量中使用 |
| append | 内置函数方法,向切片或数组添加一个或多个元素 |
| cap | 内置函数方法,获取切片或数组的容量 |
| len | 内置函数方法,获取切片或数组的长度 |
预声明标识符与关键字的区别在于:预声明标识符只设置变量的基础数据类型或使用 Go 语言内置方法,关键字定义变量、数据结构和流程控制语句。简单来讲,先使用关键字定义变量,再使用预声明标识符设置变量的数据类型,两者在使用上有明显的先后顺序。
2.2.2.3 导出标识符
导出标识符是程序导入某个包,并允许调用包中已定义的变量或函数方法。导出标识符首字符必须要大写,否则无法调用。简单来讲,就是允许在包外使用这些变量或方法
package surpass
// 这里定义的Name和Age可以surpass包外被其他包使用
var Name="Surpass"
var Age=28
type PersonInfo struct{
Name stinrg
Age int8
}
2.2.2.4 唯一标识符
在程序所有标识符集合中,每个标识符的命名与其他标识符的命名不同,则该标识符具有唯一性,可称之为唯一标识符。以下即为 3 个标识符
var name string
var Name int8
var name int8
在以上示例中,
- 第 1 个标识符为 name,数据类型为 string
- 第 2 个标识符为 Name,数据类型为 int8
- 第 3 个标识符 name,数据类型为 int8
第 1 个标识符和第 3 个标识符仅仅是数据类型不一致,因此在程序运行时,会提示错误,因为不具备唯一性。在 Go 语言是严格区分大小写,因此第 1 个和第 2 个标识符会被认为是两个标识符,因而具备唯一性。
2.2.2.5 标识符总结
| 标识符类型 | 描述 |
|---|---|
| 空白标识符 | 程序中不再被使用的变量或函数,使用下划线表示 |
| 预声明标识符 | Go 语言内置的数据类型或方法 |
| 导出标识符 | 允许其他包导入引用的标识符,首字母必须大写,类似于 Java 中 public 定义的变量或方法 |
| 唯一标识符 | 在程序具有唯一性的标识符 |
2.3 变量与常量
变量是计算机中能存储计算结果或表示值的抽象概念。变量与常量通常由标识符进行定义和使用。其主要区别如下所示:
- 变量:可以先定义后赋值,也可以在定义并同时赋值,
后续也可以进行修改 - 常量:在被定义时必须设置初始值。
后续不可以进行修改
2.3.1 变量定义与赋值
在 Go 语言定义变量的主要方法如下所示:
- 1.使用 var:只定义,不设定初始值
var variableName type
- 2.使用 var:定义并同时赋值
var variableName type = value
- 3.使用 var:批量定义多个变量
var (
variableNameA type
variableNameB type = value
)
- 4.使用 var:批量定义同一种数据类型变量
var variableNameA,variableNameB type
- 5.使用类型推断定义
variableName:= value
类型推断也称为短格式,一般仅用于函数中且不能用于定义全局变量
以上示例中 variableName 代表变量名,type 表示数据类型,value 代表变量的值
2.3.2 常量
2.3.2.1 const
在 Go 语言中,使用关键字const定义常量,主要方式如下所示:
- 1.定义单个常量
const name type = value
- 2.定义单个常量,可以省略常量类型
const name = value
- 3.一次性定义多个常量
const (
nameA type = value
nameB = value
)
- 4.一次性定义多个常量
const nameA,nameB = valueA, valueB
在 Go 语言中定义常量的注意事项如下所示:
- 在声明常量必须在定义时就必须赋值
- 在给常量赋值时,必须是能在编译器就要完全确定其值,其元素必须为不可变值,例如数组、切片等是被允许定义为常量
示例代码如下所示:
package main
import "fmt"
const Age int = 28
const Name = "Test"
const (
MyName string = "Surpass"
MyAge = 28
)
const A, B = "a", "b"
func main() {
fmt.Println("定义单个常量方式一:", Age)
fmt.Println("定义单个常量方式二:", Name)
fmt.Println("定义多个常量方式一:", MyName, MyAge)
fmt.Println("定义多个常量方式二:", A, B)
}
2.3.2.2 iota
关键字iota是一个特殊常量,它是一个可以被编译器修改的常量。iota 在关键字 const 出现时,将被重置为 0,如果关键字 const 定义了多个常量,则 iota 会为每个常量进行计数累加。示例如下所示:
package main
import "fmt"
func main() {
const a = iota //总是从0开始递增为1的整数
const b = iota
fmt.Printf("a 的值为: %d \nb 的值为: %d\n", a, b)
const ( // 批量的时候会出现递增
c = iota // iota 从第一行开始
d // Go语言中,可以重复上一行的公式,批量里面一定要注意同一个iota
e
_ // 可以用来标识符,但是不可以使用它
_ // 空白标识符,匿名变量
f
g = iota + 10 // 此时iota值为6
h // 7+10
i = 20 // 在这里iota值为 8
j
k = iota * 2 // iota 每一行iota的值处于递增状态,在这里iota值为10
l // iota值为11,因iota会重复上一行的公式,因此l的值为11*2
)
fmt.Printf("c 的值为: %d \nd 的值为: %d\ne 的值为: %d\nf 的值为: %d\ng 的值为: %d\nh 的值为: %d\ni 的值为: %d\nj 的值为: %d\nk 的值为: %d\nl 的值为: %d\n", c, d, e, f, g, h, i, j, k, l)
}
运行结果如下所示:
a 的值为: 0
b 的值为: 0
c 的值为: 0
d 的值为: 1
e 的值为: 2
f 的值为: 5
g 的值为: 16
h 的值为: 17
i 的值为: 20
j 的值为: 20
k 的值为: 20
l 的值为: 22
详细解释如下所示:
- 1.在 const 定义多个常量时,
iota从0开始计算,每多一行,自增1 - 2.
如果常量值设为iota的值,若下一个常量没有赋值,则使用iota的值 - 3.
若在定义常量值时,使用了公式,则下一个常量会自动重复上一行的公式 - 4.无论常量是否赋值,只要在 const 中定义了多个常量,
iota都会根据常量的数量进行计数 - 5.iota 只能在关键字 const 中使用,不能在关键字 const 之外使用
iota 只对 const 中定义的常量进行计数,而 iota 在 Go 语言使用比较广泛,例如,使用 iota 生成偶数等,示例代码如下所示:
const (
a = iota * 2
b
c
d
e
f
)
const (
_ = iota // 忽略第一个值
KB = 1 << (10 * iota) // 向左位移到10个二进制位,相当于2^10
MB // 相当于2^20
GB
TB
)
2.3.3 零值
如果变量已经被声明,但未被显式初始化,则变量将会设置为零值。其他语言,若只声明不初始化则会出现异常,但在 Go 语言坚持零值可用理念,常见的数据类型零值如下所示:
- int:零值为 0
- float:零值为 0.0
- bool:零值为 false
- string:零值为空串""(双引号)
- 指针类型:零值为 nil
2.4 运算符
编程语言中的运算符好似于数学中四则运算,每种编程语言都大同小异。Go 语言支持的主要运算符如下所示:
- 算术运算符:一般是指加减乘除
- 比较运算符:一般是指用来比较变量间大小
- 赋值运算符:一般是指先计算再赋值到新的变量
- 逻辑运算符:一般是指与、或、非等逻辑运算
- 位运算符 :一般是指二进制间的计算
- 其他运算符:一般是指用于指针或内存地址的操作
比较运算符有时也称之为关系运算符
2.4.1 算术运算符
算术运算符即是常见的加减乘除,通常用于简单的数学计算。Go 支持算术运算符如下所示:
| 运算符 | 功能 |
|---|---|
| + | 加法,实现两个变量相加 |
| - | 减法,实现两个变量相减 |
| * | 乘法,实现两个变量相乘 |
| / | 除法,实现两个变量相除 |
| % | 取余,实现两个变量除法的余数 |
| ++ | 自增 |
| -- | 自减 |
示例如下所示:
package main
import (
"fmt"
)
func main() {
var a, b = 28, 10
fmt.Println("a+b=", a+b)
fmt.Println("a-b=", a-b)
fmt.Println("a*b=", a*b)
fmt.Println("a/b=", a/b)
fmt.Println("a%b=", a%b)
a++
fmt.Println("a++=", a)
b--
fmt.Println("b--=", b)
}
运行结果如下所示:
a+b= 38
a-b= 18
a*b= 280
a/b= 2
a%b= 8
a++= 29
b--= 9
2.4.2 比较运算符
关系运算符常用于比较两个变量的大小,且要求两个变量的数据类型必须相同,比较的结果则返回布尔类型(true/false),常见的比较运算符如下所示:
| 运算符 | 功能 |
|---|---|
| == | 等于,用于比较两个变量是否相等 |
| != | 不等于,用于比较两个变量不相等是否成立 |
| > | 大于,用于判断比较运算符前面的变量是否大于后面的变量 |
| >= | 大于等于,用于判断比较运算符前面的变量是否大于等于后面的变量 |
| < | 小于,用于判断比较运算符前面的变量是否小于后面的变量 |
| <= | 小于等于,用于判断比较运算符前面的变量是否小于等于后面的变量 |
示例如下所示:
package main
import (
"fmt"
)
func main(){
var a,b int = 28,13
fmt.Println("a==b?",a==b)
fmt.Println("a!=b",a!=b)
fmt.Println("a>b?",a>b)
fmt.Println("a>=b?",a>=b)
fmt.Println("a<b?",a<b)
fmt.Println("a<=b?",a<=b)
}
运行结果如下所示:
a==b? false
a!=b true
a>b? true
a>=b? true
a<b? false
a<=b? false
2.4.3 赋值运算符
赋值运算符是指两个变量进行算术运算后再将其运算结果重新赋值给其中一个变量。如下所示:
| 运算符 | 功能 |
|---|---|
| = | 常规赋值运算符 |
| += | 加法赋值运算符 |
| -= | 减法赋值运算符 |
| *= | 乘法赋值运算符 |
| /= | 除法赋值运算符 |
| %= | 求余赋值运算符 |
| <<= | 左移赋值运算符 |
| >>= | 右移赋值运算符 |
| &= | 按位与赋值运算符 |
| ^= | 按位异或赋值运算符 |
| |= | 按位或赋值运算符 |
2.4.4 逻辑运算符
逻辑运算符是将多个条件进行与、或、非的逻辑判断,常用于条件判断。
| 运算符 | 功能 |
|---|---|
| && | 逻辑与,全部为 true 时,才返回 true |
| || | 逻辑或,任意一个为 true 时,均返回 true |
| ! | 逻辑非,对当前结果进行取反操作 |
2.4.5 位运算符
位运算符通常用于二进制运算。如下所示:
| 运算符 | 功能 |
|---|---|
| & | 按位与,若同为 1,则结果为 1,否则为 0 |
| | | 按位或,任意一个为 1,则结果为 1 |
| ^ | 按位异或运算,两个值不同时,则结果为 1 |
| << | 左移运算符,将二进制全部左移若干位,高位丢弃,低位补 0 |
| >> | 右移运算符,将二进制全部右移若干位,正数最高位补 0,负数最高位补 1,无符号数最高位补 0 |
2.4.6 其他运算符
Go 语言的其他运算符主要如下所示:
| 运算符 | 功能 |
|---|---|
| & | 获取变量的内存地址 |
| * | 指针变量 |
示例如下所示:
package main
import (
"fmt"
)
func main() {
var a int = 4
var ptr *int
fmt.Println("变量a的内存地址为:", &a)
ptr = &a
fmt.Println("变量ptr的内存地址为:", ptr)
fmt.Println("变量ptr的值为:", *ptr)
}
运行结果如下所示:
变量a的内存地址为: 0xc0000b6058
变量ptr的内存地址为: 0xc0000b6058
变量ptr的值为: 4
2.4.7 运算符优先级
不同的运算符有不同的优先级,在一行语句中,若使用了多种不同类型的运算符,程序会自动根据优先级决定运算的顺序。如下 所示:
| 优先级 | 运算符 | 同一运算符的优先级 |
|---|---|---|
| 1 | =,+=,-=,*= | 从右到左 |
| 2 | || | 从左到右 |
| 3 | && | 从左到右 |
| 4 | | | 从左到右 |
| 5 | ^ | 从左到右 |
| 6 | & | 从左到右 |
| 7 | ==,!= | 从左到右 |
| 8 | <,<=,>,>= | 从左到右 |
| 9 | <<,>> | 从左到右 |
| 10 | +,- | 从左到右 |
| 11 | *,/,% | 从左到右 |
| 12 | (),[] | 从左到右 |
2.5 注释
注释是对代码的解释和说明,其目的是让其他人员能更加轻松的了解代码,提高代码的可读性。Go 主要包含两种注释类型单行注释和多行注释。
2.5.1 单行注释
单行注释使用//进行注释,一般写在注释代码的上一行或同一行代码的末尾,示例如下所示:
// 这是单行注释
var name string = "Surpass"
var age int = 29 // 这也是单行注释
单行注释常用于较为简短的注释,若注释较多一行无法完成时,则优先考虑多行注释
2.5.2 多行注释
多选注释也称为块注释。常用于包文档注释或注释内容较多的场景,并且通常写于代码注释的上面,示例如下所示:
/*
你是多行注释
我也是多行注释
*/
var name string = "Surpass"
/*
多行注释
func hello(name string) string{
return "Hello"+name
}
*/
本文同步在微信订阅号上发布,如各位小伙伴们喜欢我的文章,也可以关注我的微信订阅号:woaitest,或扫描下面的二维码添加关注:

作者: Surpassme
来源: http://www.jianshu.com/u/28161b7c9995/
http://www.cnblogs.com/surpassme/
声明:本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出 原文链接 ,否则保留追究法律责任的权利。如有问题,可发送邮件 联系。让我们尊重原创者版权,共同营造良好的IT朋友圈。

浙公网安备 33010602011771号