Go 词法元素
Go 语言的 词法元素 包括 标识符 (identifier)、 关键字 (keyword)、 操作符 (operator)、 分隔符 (delimiter)、 字面量 (literal),它们是组成 Go 语言代码的最基本单位。
一、标识符
标识符是用来命名各种变量、方法、函数等程序实体的字符序列,一个标识符实际上就是一个或是多个 Unicode 字母(Unicode 标准 8.0 中的 Lu、Ll、Lt、Lm 和 Lo 分类中的字符)、Unicode 数字(Unicode 标准 8.0 中的 Nd 数字字符分类中的字符)和 _ 组成的字符序列,但是第一个字符必须是 Unicode 字母或 _。
_ 是一个特殊的标识符,称为 空白标识符 ,它可以像其他标识符那样用于变量的声明或赋值(任何类型都可以赋值给它),但任何赋给这个标识符的值都将被抛弃,因此这些值不能在后续的代码中使用,也不可以使用_ 作为变量对其它变量进行赋值或运算。
一个由 Unicode 大写字母开头的标识符称为 导出标识符 。这里导出可以被理解为公开(public)。其它(即非 Unicode 大写字母开头的)标识符称为 非导出标识符 。非导出可以被理解为私有(private)。非导出有时候也被称为未导出。
在使用标识符之前必须进行声明,声明一个标识符就是将这个标识符与常量、变量、类型、函数或者代码包绑定在一起。在同一个代码块内标识符的名称不能重复。
命名标识符时需要注意以下几点:
- 标识符的命名要尽量采取简短且有意义;
- 不能和标准库中的包名重复;
- 为变量、函数、常量命名时采用驼峰命名法,例如 stuName、getVal;
在 Go 语言中还存在着一些特殊的标识符,叫做 预定义标识符 ,一共有 36 个,包括
- 所有基本数据类型,即 int、int8、int16、int32、int64、uint、uint8、uint16、uint32、uint64、float32、float64、complex64、complex128、bool、byte、uintptr、string
- 常量 true、false、iota,零值 nil
- 所有的 内建函数 ,即 append、cap、close、copy、complex、real、imag、len、make、new、panic、print、println 和 recover
二、关键字
关键字 是被编程语言保留的字符序列,被 Go 语言赋予了特殊含义,用来帮助编译器理解和解析源代码的单词。共有 25 个包括:
- 代码元素声明:const、func、import、package、type 和 var
- 组合类型的字面表示:chan、interface、map 和 struct
- 程序流程控制:break、case、continue、default、else、fallthrough、for、goto、if、range、return、select 和 switch
- 特殊的流程控制:defer 和 go
之所以刻意地将 Go 语言中的关键字保持的这么少,是为了简化在编译过程中的代码解析。和其它语言一样,关键字不能够作标识符使用。
三、字面量
简单来说,字面量就是 值的一种标记法。但是,在 Go 中,字面量的含义要更加广泛一些。有以下 3 类。
1、用于表示基础数据类型值的 值字面量 。这是最常用的一类字面量,例如,表示浮点数类型值的 12E-3。
2、用于构造各种自定义的复合数据类型的 类型字面量。例如,下面的字面量定义了一个名称为 Name 的结构体类型:
type Name struct {
Forename string
Surname string
}
3、用于表示复合数据类型值的 复合字面量,它可以用来构造 struct(结构体)、array(数组)、slice(切片)和 map(字典)类型的值。复合字面量一般由类型以及被花括号包裹的复合元素的列表组成。例如,下面的复合字面量构造出了一个 Name 类型的值:
Name{Forename: "Robert", Surname: "Hao"}
其中 Name 表示这个值的类型,紧随其后的就是由键值对表示的复合元素列表。
四、分隔符
分隔符用来分隔 Go 语言中其它词法元素, 包括小括号、中括号、大括号、小数点、逗号、分号、冒号、省略号。
在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号结尾,因为这些工作都将由 Go 编译器自动完成。如果你打算将多个语句写在同一行,它们则必须使用分号人为区分,但在实际开发中我们并不鼓励这种做法。
五、操作符
操作符,也称 运算符 ,它是用于 数据运算 的符号。包括 算术运算符 、 关系运算符 、 逻辑运算符 、 位运算符 、 赋值运算符 、 其他运算符 。
算术运算符 (假定 A 值为 10,B 值为 20):
运算符 | 描述 | 实例 |
---|---|---|
+ | 相加 | A + B 输出结果 30 |
- | 相减 | A - B 输出结果 -10 |
* | 相乘 | A * B 输出结果 200 |
/ | 相除 | B / A 输出结果 2 |
% | 求余 | B % A 输出结果 0 |
++ | 自增 | A++ 输出结果 11 |
-- | 自减 | A-- 输出结果 9 |
关系运算符 (假定 A 值为 10,B 值为 20):
运算符 | 描述 | 实例 |
---|---|---|
== | 检查两个值是否相等,如果相等返回 True。 | (A == B) 为 False |
!= | 检查两个值是否不相等,如果不相等返回 True。 | (A != B) 为 True |
> | 检查左边值是否大于右边值,如果是返回 True。 | (A > B) 为 False |
< | 检查左边值是否小于右边值,如果是返回 True。 | (A < B) 为 True |
>= | 检查左边值是否大于等于右边值,如果是返回 True。 | (A >= B) 为 False |
<= | 检查左边值是否小于等于右边值,如果是返回 True。 | (A <= B) 为 True |
逻辑运算符 (假定 A 值为 True,B 值为 False):
运算符 | 描述 | 实例 |
---|---|---|
&& | 逻辑 AND 运算符。如果两边的操作数都是 True,则条件 True。 | (A && B) 为 False |
|| | 逻辑 OR 运算符。如果两边的操作数有一个 True,则条件 True。 | (A || B) 为 True |
! | 逻辑 NOT 运算符。如果条件为 True,则逻辑 NOT 条件 False。 | !(A && B) 为 True |
位运算符 (假定 A 为 60,B 为 13,二进制为 0011 1100、0000 1101):
运算符 | 描述 | 实例 |
---|---|---|
& | 按位与。参与运算的两数各对应的二进位相与。 | (A & B) 结果为 12, 二进制为 0000 1100 |
| | 按位或。参与运算的两数各对应的二进位相或。 | (A | B) 结果为 61, 二进制为 0011 1101 |
^ | 按位异或、按位取反。参与运算的两数各对应的二进位相异或、参与运算的数对应的二进位取反, | (A ^ B) 结果为 49, 二进制为 0011 0001、(^ A) 结果为 195, 二进制为 1100 0011, |
<< | 左移。左移 n 位就是乘以 2 的 n 次方。把 "<<" 左边的运算数的各二进位全部左移若干位,"<<" 右边的数指定移动的位数,高位丢弃,低位补 0。 | A << 2 结果为 240 ,二进制为 1111 0000 |
>> | 右移。右移 n 位就是除以 2 的 n 次方。把 ">>" 左边的运算数的各二进位全部右移若干位,">>" 右边的数指定移动的位数,高位补 0,低位丢弃。 | A >> 2 结果为 15 ,二进制为 0000 1111 |
&^ | 按位清零。同 a &(^b), 将运算符左边数据相异的位保留、相同位清零,如果右侧是 0,则左侧数保持不变,如果右侧是 1,则左侧数一定清零。 | (A &^ B) 结果为 48,二进制为 0011 0000 |
赋值运算符 :
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符,将一个表达式的值赋给一个左值 | C = A + B 将 A + B 表达式结果赋值给 C |
+= | 相加后再赋值 | C += A 等于 C = C + A |
-= | 相减后再赋值 | C -= A 等于 C = C - A |
*= | 相乘后再赋值 | C = A 等于 C = C A |
/= | 相除后再赋值 | C /= A 等于 C = C / A |
%= | 求余后再赋值 | C %= A 等于 C = C % A |
<<= | 左移后赋值 | C <<= 2 等于 C = C << 2 |
>>= | 右移后赋值 | C >>= 2 等于 C = C >> 2 |
&= | 按位与后赋值 | C &= 2 等于 C = C & 2 |
^= | 按位异或后赋值 | C ^= 2 等于 C = C ^ 2 |
|= | 按位或后赋值 | C |= 2 等于 C = C | 2 |
其他运算符 :
运算符 | 描述 | 实例 |
---|---|---|
& | 返回变量存储地址 | &a; 将给出变量的实际地址。 |
* | 指针变量。 | *a; 是一个指针变量 |
<- | 管道操作符。 | <-a; 从管道 a 中获取一个元素 |
运算符优先级
有些运算符拥有较高的优先级,二元运算符的运算方向均是从左至右。
优先级 | 运算符 |
---|---|
7 | ^ ! |
6 | * / % << >> & &^ |
5 | + - | ^ |
4 | == != < <= >= > |
3 | <- |
2 | && |
1 | || |
注意 :
- 优先级值越大,表示优先级越高。
- Go 语言中按位取反和按位异或的操作符都是 ^, 按位取反的优先级为 7,按位异或的优先级为 5
- 双目运算符可以和等号复合成赋值运算符
- Go 语言中大部分运算符的优先级和数学中是一样的,如果实在不清楚,可以加括号来临时提升优先级
- Go 的自增、自减只有 a ++、a--,不存在 ++a、--a。
- Go 的自增、自减只能作为表达式使用,而不能用于赋值语句,a = a++ 这是不允许的。
- 相加运算符,也可以完成字符串的连接运算,例如 "hello" + "" +"world!"。