前言
GO语言是由Google开发的一门开源编程语言,它的设计目标是简洁高效。GO语言作为一门静态类型、编译型语言,兼具了高效的执行速度和易于开发维护的特性。在本篇博客中,我们将深入探讨GO语言的基础语法,重点突出其独特之处以及如何利用这些特性编写优雅的代码。
Go词法单元
在介绍 Go 语言具体语法之前,先介绍一下现代高级语言的源程序内部的几个概念: token 、
关键字、标识符、操作符、 分隔符和字面量。这种语言层面通用的概念非常重要,这些概念能够帮助程序员更好地掌握语言的语法结构 。
token
token 是构成源程序的基本不可再分割的单元。编译器编译源程序的第一步就是将源程序分割为一个个独立的 token,这个过程就是词法分析。 Go 语言的 token 可以分为关键字、标识符 、操作符、分隔符和字面常量等。
Go 语言里面的 token 是怎么分割的昵? Go 的 token 分隔符有两类 : 一类是操作符,还有一类自身没有特殊含义,仅用来分隔其他 token ,被称为纯分隔符。
- 操作符: 操作符就是一个天然的分隔符,同时其自身也是一个 token, 语句如下所示 。
sum := a + b
“:=”和“+”既是分隔符,也是token,所有这个简单的语句被分割为5个token:“sum”、“:=”、“a”、“+”、“b”。
- 纯分隔符: 其本身不具备任何语法含义,只作为其他 token 的分割功能。包括空格、制表符、换行符和回车符 , 多个相邻的空格或者制表符会被编译器看作分隔符处理,比如如下语句
package main
这是一个包声明的语句, package 和 main 之间可以有任意多个空格或者制表符 , Go 编译器会将其作为一个分隔符处理,最后分离出来两个token:package 和 main 。
标识符
编程语言的标识符用来标识变量、类型 、 常量等语法对象的符号名称,其在语法分析时作为一个 token 存在 。编程语言的标识符总体上分为两类 : 一类是语言设计者预留的标识符, 一类是编程者可以自定义的标识符。 前者一般由语言设计者确定 , 包括语言的预声明标识符及用于后续言扩展的保留字;后者是用户在编程过程中自行定义的变量名、常量名、函数名等一切符合语言规范的标识符。
Go 的标识符构成规则是: 开头一个字符必须是字母或下划线,后面跟任意多个字符、数字或下划线 , 并且区分大小写, Unicode 字符也可以作为标识符的构成,但是一般不推荐这么使用。我们在定义新的标识符时要避开 Go 语言预声明标识符,以免引起混乱。
9aa //这不是一个合法标识符,不是以字母或下画线开头
-aa //这不是一个合法标识符,不是以字母或下画线开头
aa //这是一个合法标识符
_aa //这是一个合法标识符
aa911 //这是一个合法标识符
_aa911 //这是一个合法标识符
Go 语言预声明的标识符包括关键字、内置数据类型标识符、常量值标识符 、 内置函数和空白标识符。在写 Go 源程序的过程中,用户自定义标识符用在包名、函数名 、 自定义类型名、变量名和常量名等上。
关键字( 25个 )
编程语言里面的关键字是指语言设计者保留的有特定语法含义的标识符,这些关键宇有自己独特的用途和语法含义,它们一般用来控制程序结构,每个关键字都代表不同语义的语法糖 。Go 语言是一门极简的语言,只有如下 25 个关键字 :
break、default、func、interface、select
case、defer 、go、map、struct
chan、else、goto、package、switch
const、fallthrough、if、range、type
continue、for、import、return、var
内置数据类型标识符( 20个 )
丰富的内置类型支持是高级语言的基本特性,基本类型也是构造用户自定义类型的基础。为了标识每种内置数据类型,Go 定义了一套预声明标识符,这些标识符用在变量或常量声明时。Go 语言内置了 20 个预声明数据类型标识符。
数值( 16 个)
整型( 12 个)
byte int int8 int16 int32 int64
uint unint8 uint16 uint32 uint64 uintprt
浮点型( 2 个)
float32 float64
复数型( 2 个)
complex64 complex128
字符和字符串型( 2 个)
string rune
接口型( 1 个)
error
布尔型( 1 个)
bool
Go 是一种强类型静态编译型语言,在定义变量和常量时需要显式地指出数据类型,当然Go 也支持自动类型推导,在声明初始化内置类型变量时, Go 可以自动地进行类型推导。但是在定义新类型或函数时,必须显式地带上类型标识符 。
内置函数( 15个 )
make new len cap append copy delete panic recover close complex real image
Print Println
内置函数也是高级语言的一种语法糖,由于其是语言内置的,不需要用 import 引入,内置
函数具有全局可见性 。 注意到其都是以小写字母开头的,但是并不影响其全局可用性 。
常量值标识符( 4个)
true false //true 和 false 表示 bool 类型的两常量值:具和假
iota //用在连续的枚举类型的声明中
nil //指针/引用型的变量的默认值就是 nil
Go 的常量值标识符代表的是一个常量值,这个常量值表达特殊的含义,不好使用常量字面量直接表述时,就使用 一个预先声明的标识符代替。
空白标识符( 1个 )
_
空白标识符有特殊的含义,用来声明-个匿名的变量,该变量在赋值表达式的左端,空白标识符引用通常被用作占位,比如忽略函数多个返回值中的一个和强制编译器做类型检查。
操作符和分隔符
操作符就是语言所使用的符号集合, 包括运算符、显式的分隔符,以及其他语法辅助符号。操作符不但自身是一个 token,具备语法含义,同时其自身也是分隔其他 token 的分隔符。另外还有一类分隔符本身没有什么含义,仅仅起到分隔 token 的功能,这里纯粹的分隔符有 4 个:空格、制表符、回车和换行。
分隔符可以细分如下几类。
算术运算符( 5 个 )
算术计算顺序是按照优先级从左到右进行的, 当然也可以使用括号来改变操作数的结合顺序。
+ - * / %
- 位运算符( 6 个 )
& | ^ &^ >> <<
- 赋值和赋值复核运算符 ( 13 个 )
:= = += -= *= /= %= &= |= ^= &^= >>= <<=
- 比较运算符( 6 个 )
> >= < <= == !=
- 括号( 6 个 )
( ) { } [ ]
- 逻辑运算符( 3 个 )
&& || !
- 自增自减操作符( 2 个)
++ --
注意:Go语言里面自增、自减操作符是语句而不是表达式
- 其他运算符( 6 个 )
: , ; . ... <-
字面常量
编程语言源程序中表示固定值的符号叫作字面常量,简称字面量。 一般使用裸字符序列来表示不同类型的值。字面量可以被编程语言编译器直接转换为某个类型的值。 Go 的字面量可以出现在两个地方:一是用于常量和变量的初始化, 二是用在表达式里或作为函数调用实参。变量初始化语句中如果没有显式地指定变量类型 ,则 Go 编译器会结合字面量的值自动进行类型推断。 Go 中的字面量只能表达基本类型的值, Go 不支持用户定义的字面量。
字面量有如下几类:
整型字面量
整型字面量使用特定字符序列来表示具体的整型数值,常用于整型变量或常量的初始化。
浮点型字面量
浮点型字面量使用特定字符序列来表示一个浮点数值。它支持两种格式 : 一种是标准的数学记录法,比如0.1; 另一种是科学计数法的表示,比如 1E6。
复数类型字面量
复数类型字面量使用特定的字符序列来表示复数类型的常量值。
字符型字面量
Go 的源码采用的是 UTF心的编码方式, UTF- 8 的宇符占用的字节数可以有 l ~4 个字节,
Rune 宇符常量也有多种表现形式,但是使用“ ’ ’ ”(单引号)将其括住。
字符串字面量
字符串字面量的基本表现形式就是使用“ " " ”将字符序列包括在内,双引号里面可以是UTF- 8 的字符字面量 ,也可以是其编码值 。
变量和常量
高级语言通过一个标识符来绑定一块特定的内存,后续对特定的内存的操作都可以使用该标识符来代替。这类绑定某个存储单元的标识符又可以分为两类,一类称之为“变量”,一类称之为“常量”。顾名思义,变量表示指向的内存可以被修改,常量表示指向的内存不能被修改。
变量
变量:使用一个名称来绑定一块内存地址 , 该内存地址中存放的数据类型由定义变量时指定的类型决定,该内存地址里面存放的内容可以改变。
Go 的基本类型变量声明有两种。
1. 显式的完整声明
var varName dataType [ = value]
- 关键字var用于变量声明
- varName是变量名标识符
- dataType是基本类型
- value是变量的初始值,初始值可以是字面量,也可以是其他变量名,还可以是一个表达式;如果不指定初始值,则Go默认将该变量初始化为类型的零值。
- Go的变量声明后就会立即为其分配空间。
var a int = 1 var a int = 2*3 var a int = b
2.短类型声明
varName := value
- := 声明只能出现在函数内(包括在方法内)。
- 此时Go编译器自动进行数据类型推断。
Go支持多个类型变量同时声明并赋值。例如:
a,b := 1,"hello"
变量具有如下几个属性。
变量名
Go 中使用自定义标识符来声明一个变量。
变量值
变量实际指向的是地址里存放的值,变量的值具体怎么解析是由变量的类型来决定的。在初始化变量值时,我们可以使用字面量,也可以使用其他的变量名。
变量存储和生存期
Go 语言提供自动内存管理,通常程序员不需要特别关注变量的生存期和存放位置 。编译器使用栈逃逸技术能够自动为变量分配空间 : 可能在栈上,也可能在堆上 。
类型信息
类型决定了该变量存储的值怎么解析,以及支持哪些操作和运算,不同类型的变量支持的操作和运算集是不一样的。
可见性和作用域
Go 内部使用统一的命名空间对变量进行管理,每个变量都有一个唯一 的名字,包名是这个名字的前缀。