第2章 Go语言编程基础
2.1 数据类型
2.1.1 基础数据类型
Go语言的数据类型可以用于参数和变量声明,可以分为如下五类:
- 布尔类型:只可以是常量true或者false。
- 数字类型:整型int和浮点型float32,float64。
- 字符串类型:字符串类型是一串固定长度的字符连接起来的字符序列。
- 复合(派生)类型:包括指针类型(pointer)、数组类型(array)、结构类型(struct)、通道类型(channel)、函数类型(function)、切片类型(slice)、接口类型(interface)和字典类型(map)。
- 错误类型(error):error类型是Go语言预定义类型。
2.1.2 复合数据类型
Go语言中含有多种复合数据类型,将会在下面的章节中逐个进行讲解。
2.2 变量
2.2.1 变量以及声明
Go语言中由四类标记:标识符(identifiers)、关键字(keywords)、运算符(operators)标点符号(punctuation)以及字面量(literals)。
Go语言的变量标识符由字母、数字、下划线组成,其中首字符不能为数字,变量区分大小写。
变量声明形式有三种:
1)单独声明
var year int
2)联合声明
var (
year int
month int
day int
hour, minute, second int
)
3)推断式声明
year, month, day := 2020, 1, 1 //year,month,day未加声明,但会被推断为int类型
2.2.2 零值(nil)
当一个变量被var声明之后,如果没有对其明确指定初始值,Go语言会自动化其值为一个对应的零值。
类型 | 零值 |
---|---|
integer | 0 |
float | 0.0 |
bool | false |
string | 空字符串 “” |
pointer interface, error, function, map, slice, channel | nil |
2.3 常量
2.3.1 常量定义
常量使用const关键字定义,用于存储不变的数字,不可以被重新赋予任何值。
常量只可以是布尔型、数字型和字符串三种类型,定义形式如下:
const identifier [type] = value
例如:
const a string = "abc"
const b = 123
cosnt c = true
2.3.2 iota
iota比较特殊,可以认为是一个能被编译器修改值得常量,特性如下:
- 每一个const出现时,被赋值为0
- iota的值,随行数增长,每次加1
基于上述特性,iota常被用于作枚举值:
const (
// const 定义时,自动集成上一行的值
a1 = iota // iota = 0, a1 = 0 = iota
b1 // iota = 1, b1 = 1 = iota
c1 // iota = 2, c1 = 2 = iota
)
const (
// 遇到const时iota自动赋值为0,且随行数增加自动加1
a2 = iota // iota = 0, a2 = 0 = iota
b2 = 8 // iota = 1, b2 = 8
c2 // iota = 2, c2 = 8
d2 = iota // iota = 3, d2 = 3 = iota
)
const (
// const 定义时,自动集成上一行的值
a3, b3 = iota, iota + 1 // iota = 0, a3 = 0, b3 = 1
c3, d3 = // iota = 1, c3 = 1, d3 = 2
)
2.3.3 字面量
在Go语言中,字面量是指由字母、数字等构成的字符串或数值,它只能作为右值出现。
由下面几种字面量
- 整数字面量(Iiterals)
42 //十进制
0600 //八进制
0xBadFace //十六进制
0XBadFace //十六进制
- 浮点数字面量(Floating-point literals)
7.
7.2
.2
7.2e+1
7.2e1
7.2E+1
7.2E1 //e+1, e1, E+1, E1 都代表前面数字×10
- 虚数字面量(Imaginary literals)
7i
.2i
7.2i
- Rune字面量(Rune Iiterals)
Rune字面量是标识符Unicode代码点的整数值。Rune字面量表示用单引号括起来的一个或多个字符,如’x’或’\n’。在单引号内,除了换行符和未转义的单引号外,任何字符都可以出现。
特别的,几种反斜杠转义允许将任意值编码为ASCII文本:
1)\x后跟恰好两个十六进制数字;
2)\u后跟恰好四个十六进制数字;
3)\U后跟恰好八个十六进制数字;
4)\后跟恰好三个八进制数字。 - 字符串字面量(String literals)
字符串字面变量表示通过连接字符序列获得字符串常量。有两种形式:原始字符串字面量和解释字符串字面量。
原始字符串字面量是反引号之间的字符序列。
解释的字符串字面量是双引号直接的字符序列
2.4 运算符
2.4.1 内置运算符
- Go语言的算术运算符
运算符 | 含义 |
---|---|
+ | 相加 |
- | 相减 |
* | 相乘 |
/ | 相除 |
% | 求余 |
++ | 自增 |
– | 自减 |
- Go语言的关系运算符
运算符 | 含义 |
---|---|
== | 相等 |
!= | 不等 |
> | 大于 |
< | 小于 |
>= | 大于等于 |
<= | 小于等于 |
- Go语言的逻辑运算符
运算符 | 含义 |
---|---|
&& | 逻辑与 |
|| | 逻辑或 |
! | 逻辑非 |
- Go语言的位运算符
运算符 | 含义 |
---|---|
& | 按位与 |
| | 按位或 |
^ | 按位异或 |
<< | 左移 |
>> | 右移 |
- Go语言的赋值运算符
运算符 | 含义 |
---|---|
= | 简单赋值 |
+= | 相加后赋值 |
-= | 相减后赋值 |
*= | 相乘后赋值 |
/= | 相除后赋值 |
%= | 求余后赋值 |
<<= | 左移后赋值 |
>>= | 右移后赋值 |
&= | 按位与后赋值 |
^= | 按位异或后赋值 |
= | 按位或后赋值 |
- Go语言的其他运算符
运算符 | 含义 | 效果 |
---|---|---|
& | 返回变量存储地址 | &a 将给出变量的实际地址 |
* | 指针变量 | *a 是一个指针变量 |
2.4.2 运算符优先级
一元运算符具有最高优先级。
二元运算符具有五个优先级,优先级高者先运算:
优先级 | 运算符 |
---|---|
5 | * / % << >> & &^ |
4 | + - |
3 | == != < <= > >= |
2 | && |
1 | || |
2.4.3 几个特殊运算符
- &^ 位清符
将制定位置上的值设为0,x&^y = x&(^y) - ^ 异或(XOR)
^作为一元运算符出现时,为按位取反的意思。
2.5 字符串
2.5.1 字符串介绍
Go语言中可以使用反引号或长双引号来定义字符串。
- 反引号:字符串使用反引号括起来,其中的相关转义字符不会被替换。
- 双引号:字符串使用双引号括起来,其中的相关转义字符会被替换。
Go语言中的string类型是一种值类型,存储的字符串是不可改变的,如果要修改string的内容,需要将string转换为[]byte或[]rune,并且修改后的string内容是重新生成的。
type byte = uint8
type rune = int32
string的零值是长度为零的字符串,即空字符串""。
一般的比较符,通过在内存中按字节比较来实现字符串的对比。
可以通过函数len()获取字符串所占的字节长度。
可以通过[]来索引字符串的字节,索引从0开始:
- 字符串str的第一个字节: str[0]
- 第i个字节:str[i-1]
- 最后一个字节str[len(str) - 1]
Go语言默认使用UTF-8编码,对Unicode的支持也非常好。但是len( )获取的是UTF-8编码的长度,而不是直接获取字符数量。
2.5.2 字符串拼接
- 直接使用运算符
str := "abc" + "def"
- mt.Sprintf()
str = fmt.Sprintf("%d%s", 123, "abc")
- strings.join()
str = strings.Join([]string{"abc","def"}, "123")
- bytes.Buffer
var buffer bytes.Buffer
buffer.
- strings.Builder
var buf strings.Builder
buf.WriteString("abc")
buf.WriteString("def")
str := buf.String()
2.5.3 字符串处理
标准库中有四个包对字符串进行处理非常重要:bytes, strings, strconv 和 unicode
- strings包提供了许多字符串查询、替换、比较、截断、拆分和合并等功能。
- bytes包提供了很多类似的功能函数,但是针对和字符串有相同结构的 [ ]byte类型。
- strconv包提布尔型、整数型、浮点数和对应字符串的转换,还提供了双引号转义的相关函数。、
- unicode包提供了IsDigit,IsLetter,IsUpper和IsLower等类似功能,用于给字符分类。
2.6 流程控制
2.6.1 switch语句
switch语句提供多路执行,将表达式或类型说明符与“switch”内的“case”进行比较,以确定需要执行的分支。
switch有两种形式:表达式型switch和类型型switch。在表达式型switch中,包含与switch表达式的值进行比较的表达式;在类型型switch中,包含与switch表达式的类型进行比较的类型。
Go语言中,switch的每个分支默认带有break,如果需要继续执行可以使用fallthrough强制执行下一条分支的代码,并忽略分之前表达式的结果是否正确。特别的,switch的最后一个分支不可以使用fallthrough。
switch主要有三种形式:
- switch后接一个表达式
switch var1 {
case val1:
...
case val2:
...
default:
...
}
- switch后不接任何东西,相当于switch true
switch{
case condition1:
...
case condition2:
...
default:
...
}
- switch后接一个初始化语句
switch initialization{
case val1:
...
case val2:
...
default:
...
}
特别的,switch后接类型
switch x.(type){
case type1:
statement(s);
case type2:
statement(s);
/* 你可以定义任意个数的case */
default: /* 可选 */
statement(s);
}
2.6.2 select语句
select是Go语言中的一个控制结构,类似于switch语句,每个case必须是一个通信操作,要么是发送要么是接收。
select随机执行一个可运行的case,如果没有case可以运行,它将阻塞,直到case可运行,default是一个默认的字句应该总是可以运行。
select {
case communication clause :
statement(s);
case communication clause :
statement(s);
/* 你可以定义任意数量的 case */
default : /* 可选 */
statement(s);
}
特别的:
- 每个case都是一个通信
- 所有channel表达式都会被求值
- 所有发送的表达式都会被求值
- 如果任意某个通信可以进行,他就会执行,其他被忽略
- 如果多个case都可以运行,select会随机公平地选择出一个执行,其他不会执行。
- 若没有可执行的case,则默认执行default子句
- 若没有default子句,select将阻塞,直到某个通信可以进行;Go 不会重新对 channel 或值进行求值。
2.6.3 for语句
for语句是最简单的基于计数器的循环迭代,基本形式为:
for 初始化语句; 条件语句; 修饰语句{
......
}
2.6.4 for-range结构
for range 结构是Go语言特有的一种迭代结构,它在许多情况下都非常有用。它可以迭代任何一个集合,包括数组和字典,同时可以带带对应的索引和值,一般形式为:
for ix, val := range coll {
......
}
2.6.5 if语句
if语句是由布尔表达式紧跟一个或多个语句组成。特别的,布尔表达式不用()。
一般形式为:
if 布尔表达式{
......
} else {
......
}
2.6.6 break语句
一个break的作用范围为该语句出现后的最内部结构,他可以用于任何的非顺序语句。
但在switch或select语句中,break语句的作用是跳过整个代码块。
2.6.7 continue语句
关键字continue忽略剩余的循环体而直接进入下一次循环的过程,但是不是无条件的执行下一次循环,执行之前依旧要满足循环条件。
2.6.8 标签
for、switch或select语句都可以配合标签(label)形式的标识符使用,即某一行第一个以冒号结尾的单词。标签的名称是大小写敏感的,为了提高可读性,一般建议全用大写字母。
ERROR:
log.Panic("error encountered")
2.6.9 goto语句
goto语句就是调到具有相同函数内响应标签的语句。
goto ERROR
破坏代码结构的完整性,不鼓励使用。
来源:CSDN
作者:WXY_supn
链接:https://blog.csdn.net/WXY_supn/article/details/103553374