文章目录
- [1. 初识Go语言](#1. 初识Go语言)
-
- [1.1 语言介绍](#1.1 语言介绍)
- [1.2 环境搭建](#1.2 环境搭建)
- [1.3 执行流程](#1.3 执行流程)
- [1.4 转义字符](#1.4 转义字符)
- [1.5 规范的代码风格](#1.5 规范的代码风格)
- [1.5 常见问题和解决方法](#1.5 常见问题和解决方法)
- [2. Go的概述](#2. Go的概述)
-
- [2.1 程序](#2.1 程序)
- [2.2 指令](#2.2 指令)
- [3. 变量](#3. 变量)
-
- [3.1 概念](#3.1 概念)
- [3.2 全局变量](#3.2 全局变量)
- [4. 数据类型](#4. 数据类型)
-
- [4.1 基本数据类型](#4.1 基本数据类型)
-
- [4.1.1 数值类型](#4.1.1 数值类型)
-
- [4.1.1.1 整数类型](#4.1.1.1 整数类型)
- [4.1.1.2 浮点类型](#4.1.1.2 浮点类型)
- [4.1.2 字符型](#4.1.2 字符型)
- [4.1.3 布尔型](#4.1.3 布尔型)
- [4.1.4 字符串](#4.1.4 字符串)
- [4.1.5 相互转换](#4.1.5 相互转换)
-
- [4.1.5.1 介绍](#4.1.5.1 介绍)
- [4.1.5.2 基本语法](#4.1.5.2 基本语法)
- [4.1.5.3 转换细节](#4.1.5.3 转换细节)
- [4.1.5.4 基本数据类型和String互相转换](#4.1.5.4 基本数据类型和String互相转换)
- [4.2 派生/复杂数据类型](#4.2 派生/复杂数据类型)
-
- [4.2.1 指针](#4.2.1 指针)
- [4.2.2 数组](#4.2.2 数组)
- [4.2.3 结构体-golang支持面向对象变成特性](#4.2.3 结构体-golang支持面向对象变成特性)
-
- [4.2.3.1 面向对象说明](#4.2.3.1 面向对象说明)
- 4.2.3.2结构与结构体变量的区别
- [4.2.3.3 声明结构体](#4.2.3.3 声明结构体)
- [4.2.3.4 创建结构体和访问结构体字段](#4.2.3.4 创建结构体和访问结构体字段)
- [4.2.3.5 使用细节和注意事项](#4.2.3.5 使用细节和注意事项)
- [4.2.4 管道](#4.2.4 管道)
- [4.2.5 函数](#4.2.5 函数)
-
- [4.2.5.1 基本介绍](#4.2.5.1 基本介绍)
- [4.2.5.2 调用机制](#4.2.5.2 调用机制)
-
- [4.2.5.2.1 调用过程](#4.2.5.2.1 调用过程)
- [4.2.5.2.2 return语句](#4.2.5.2.2 return语句)
- [4.2.5.3 递归调用](#4.2.5.3 递归调用)
- 4.2.5.4init函数
- [4.2.5.5 匿名函数](#4.2.5.5 匿名函数)
- [4.2.5.6 闭包](#4.2.5.6 闭包)
- [4.2.5.7 defer](#4.2.5.7 defer)
- [4.2.5.8 参数传递方式](#4.2.5.8 参数传递方式)
- 4.2.5.9变量作用域
- 4.2.5.10内置函数-builtin
- [4.2.6 切片slice](#4.2.6 切片slice)
-
- [4.2.6.1 基本语法](#4.2.6.1 基本语法)
- [4.2.6.2 长度](#4.2.6.2 长度)
- [4.2.6.3 内存中的形式](#4.2.6.3 内存中的形式)
- 4.2.6.4使用
- 4.2.6.5遍历
- 4.2.6.6注意事项和使用细节
- 4.2.6.7字符串string和切片slice
- 4.2.7接口
- 4.2.8map
- 4.3值类型和引用类型
- [5. 标识符的命名规范](#5. 标识符的命名规范)
- [6. 运算符](#6. 运算符)
-
- [6.1 算术运算符](#6.1 算术运算符)
- [6.2 赋值运算符](#6.2 赋值运算符)
- [6.3 比较/关系运算符](#6.3 比较/关系运算符)
- [6.4 逻辑运算符](#6.4 逻辑运算符)
- [6.5 位运算符](#6.5 位运算符)
- [6.6 其它运算符](#6.6 其它运算符)
-
- [6.6.1 &](#6.6.1 &)
- [6.6.2 \*](#6.6.2 *)
- [6.7 运算符优先级](#6.7 运算符优先级)
- [6.8 键盘输入语句](#6.8 键盘输入语句)
- [7. 流程控制](#7. 流程控制)
-
- [7.1 顺序控制](#7.1 顺序控制)
- [7.2 分支控制---if-else](#7.2 分支控制—if-else)
-
- [7.2.1 单分支](#7.2.1 单分支)
- [7.2.2 双分支](#7.2.2 双分支)
- [7.2.3 多分支](#7.2.3 多分支)
-
- [7.2.3.1 嵌套分支](#7.2.3.1 嵌套分支)
- 7.2.3.2switch分支
- [7.3 循环控制](#7.3 循环控制)
-
- [7.3.1 for循环](#7.3.1 for循环)
- [7.3.2 while和do...while实现](#7.3.2 while和do...while实现)
-
- [7.3.2.1 while](#7.3.2.1 while)
- [7.3.2.1 do...while](#7.3.2.1 do...while)
- [7.4 跳转控制语句](#7.4 跳转控制语句)
-
- [7.4.1 break](#7.4.1 break)
- [7.4.2 continue](#7.4.2 continue)
- [7.4.3 goto](#7.4.3 goto)
- [7.4.4 return](#7.4.4 return)
- [8. 包](#8. 包)
-
- [8.1 原理](#8.1 原理)
- [8.2 介绍](#8.2 介绍)
- [9. 错误处理机制](#9. 错误处理机制)
1. 初识Go语言
1.1 语言介绍
1.定义
2009年11月10日,Go语言(Golang)是云计算时代的C语言。
2.优点
-
可直接编译成机器码,不依赖其他库,部署简单。
-
静态类型语言,可以在编译的时候检查出来隐藏的大多数问题。有动态语言感觉
-
语言层面支持并发。
-
内置runtime,支持垃圾回收(垃圾回收机制:GC)。
-
丰富的第三方库。
-
函数可以返回多个值
-
切片、延时执行defer
3.使用场景
-
服务编程
-
分布式系统,数据库代理器
-
网络编程
-
内存数据库
-
云平台
-
区块链的应用
-
后端服务器应用
-
云计算/云服务后台应用
1.2 环境搭建
1.安装和设置SDK(Software Development Kit 软件开发工具)
注意:安装路径不要有中文和特殊符号。
2.配置环境变量

1.3 执行流程


编译:
- go build -o 新文件名 go文件

1.4 转义字符
-
\t:一个制表符
-
\n:换行
-
\:\
-
\r:回车
-
":一个"
1.5 规范的代码风格
-
正确的注释和注释风格
-
推荐使用行注释
-
正确的缩进和空白
-
使用一次tab操hu作,实现缩进,使用shift+tab向前缩进
-
gofmt进行格式化------gofmt 文件名 /gofmt -w 文件名(可以将格式化后的额内容写入该文件)
1.5 常见问题和解决方法

2. Go的概述
2.1 程序
完成某个功能的指令的集合。
2.2 指令
为了让计算机执行某些操作或解决某个问题而编写的一系列有序指令的集合。
3. 变量
3.1 概念
1.相当于内存中一个数据存储空间。
2.使用步骤:
-
声明变量
-
赋值
-
使用
3.注意事项
-
变量表示内存中的一个存储区域
-
该区域有自己的名称和类型
-
使用的三种反射光hi
-
指定变量类型,声明后若不赋值,使用默认值(又叫零值)
-
int默认值:0
-
string默认值:空
-
float默认值:0
-
bool默认值:false
-
指针、slice和map的默认值:nil
-
-
根据值自行判定变量类型(类型推导)
-
省略var,注意:=左侧的变量不应该是已经声明过的,否则会导致编译错误
-
多变量声明
go
// 方法一:声明一个变量 默认值是0
var a int
fmt.Println("a = ", a)
fmt.Printf("type of a =%T\n", a)
// 方法二:声明一个变量,赋初始值
var b int = 200
fmt.Println("b = ", b)
fmt.Printf("type of b =%T\n", b)
// 方法三:初始化时省去数据类型,通过值自动匹配当前变量的数据类型
var c = "hello"
fmt.Println("c = ", c)
fmt.Printf("type of c =%T\n", c)
// 方法四:省去var关键字,直接自动匹配
d := 288
fmt.Println("d = ", d)
fmt.Printf("type of d =%T\n", d)
//一次声明多个变量
var n1,n2,n3 int
var n1, name, n3 = 100, "toom", 88
n1, name, n3 := 100, "toom", 88
-
该区域的数据值可以在同一类型范围内不断变化
-
变量在统一作用域内不能重名
-
变量三要素:变量=变量名+值+数据类型
3.2 全局变量
go
// 全局变量
// 方式一
var n1 = 20;
var n2 = "tom"
// 方式二
var (
n1 = 20,
n2 = "tom"
)
4. 数据类型

4.1 基本数据类型
4.1.1 数值类型
4.1.1.1 整数类型
1.用于存放整数。
2.分类:
-
有符号:
-
无符号:
-
其他类型:
3.使用细节
-
整数类型分为有符号和无符号,int uint的大小和系统有关
-
整型默认声明为int型
-
某个变量占用字节大小和数据类型
go
import (
"fmt"
"unsafe"
)
// 变量占用字节大小和数据类型
var s int8= 9
fmt.Printf("s 的数据类型 %T,占用字节数 %d",s,unsafe.Sizeof(s))
-
整型变量在使用时,遵守保小不保大的原则,即在保证程序正常运行下,尽量使用占用空间小的数据类型
-
bit:计算机中最小存储单位,byte:基本存储单元。
4.1.1.2 浮点类型
1.分类

2.注意事项
-
浮点数在机器中存放形式:浮点数=符号位+指数位+尾数位
-
尾数可能丢失,造成精度损失。
-
存储部分分为i三部分,符号位+指数位+尾数位,在存储过程中精度会丢失。
-
float64比float32更精确
3.使用细节
-
有固定范围和字段长度,不受具体os操作系统的影响
-
浮点类型默认声明位float64类型
-
表示形式
-
十进制数形式(必须有小数点)
-
科学计数法形式
-
通常使用float4,比float32更精确
4.1.2 字符型
1.没有专门的字符类型,如果要存储单个字符(字母),一般使用byte来保存---保存的时对应的ASCII码。
2.go的字符串由字节组成。
3.使用细节
-
字符常量使用单引号
-
允许使用转义字符\将其后的字符转变为特殊字符型常量
-
字符使用UTF-8编码(英文一个字节,中文3个字节)
-
字符的本质是一个整数,直接输出时是该字符对应的UTF-8编码的码值
-
可以直接给某个变量赋一个数字,然后按格式化输出%c,会输出该数字对应的unicode字符
-
字符类型可以进行运算,相当于一个整数,因为都有unicode码
go
var n1 = 10 + 'a' //10 + 97 = 107
4.本质讨论
-
字符型存储到计算机中,需要将字符对应的码值(整数)找出来
-
存储:字符-》码值-》二进制-》存储
-
读取:二进制-》码值-》字符-》读取
-
字符和码值对应关系是通过字符比那吗决定的
4.1.3 布尔型
1.占一个字节
2.使用细节:不可以用0或非0的整数替代false和true
4.1.4 字符串
1.字符串是由的单个字节连接起来。
2.使用细节
-
字符串的字节使用utf-8编码表示unicode文本,不会出现乱码
-
字符串一旦赋值,即不能修改。go中的字符串不可变
go
var str = "hello"
fmt.Println(str)
str[0] = 'a' //这里不能修改string的内容
-
两种表示形式
-
双引号:会识别转义字符
-
反引号:以字符串的原生形式输出,包括换行符和特殊字符。
-
拼接方式
-
当一行字符太长时,需要使用多行字符串---将+留在上一行

3.常用函数
-
len(str):统计字符串长度,按字节
-
\]rune()str:字符串遍历,同时处理有中文的问题
-
strconv.Itoa(12):整数转字符串
-
\]byte("hello"):字符串转\[\]byte
-
strconv.FormatInt(123,2):10进制转2,8,16进制
-
strings.Contains("sead","e"):查找字符串中是否存在指定的子串
-
strings.EqualFold(""abc","Abc"):不区分大小写的字符串比较
-
string.Index("ndscs","nd):返回字串在字符串第一次出现的index值,如果没有返回-1
4.1.5 相互转换
4.1.5.1 介绍
需要显示转换(强制转换),不能自动转换。
4.1.5.2 基本语法
表达式T(v)将值v转换位类型T。
T:数据类型
v:需要转换的变量。
go
var i int = 32;
// 将i=》float
var n1 float32 = float32(i)
4.1.5.3 转换细节
-
转换可以从表示范围小->范围大,也可以范围大-》范围小
-
被转换的是变量存储的数据,变量本身的数据类型并没有变化
-
转换中,比如将int64转换为int8,编译时不会报错,只是将转换的结果按溢出处理
4.1.5.4 基本数据类型和String互相转换
1.相互转换
-
基本数据类型------》String
-
fmt.Sprintf("%参数",表达式)
-
strconv包的函数

-
String------》基本数据类型
-
strconv包的函数

注意:返回值需要根接收的值保持统一,如果需要在转换,则可进一步进行转换。

-
转换细节
-
确保String类型能够转成有效的数据
4.2 派生/复杂数据类型
4.2.1 指针
4.2.1.1基本介绍
-
基本数据类型:变量存的是值,也叫值类型
-
获取变量的地址,用&
go
var i int =10
// &i 存的就是地址

- 指针类型:指针变量存的是一个地址,这个地址指向的空间存的才是值。
go
var i int = 10
var ptr *int = &i

- 获取指针类型所指向的值,用*
go
var i int = 10
var ptr *int = &i
// *ptr取出ptr指向的值
eg:
go
package main
import "fmt"
func main() {
//获取一个int变量num的地址
var num int = 9
fmt.Printf("num 的地址 %v", &num)
// 通过*ptr修改num的值
var ptr *int
ptr = &num
*ptr = 10
fmt.Println("num= ", num)
}

4.2.1.2使用细节
-
值类型都有对应的指针类型,形式为*数据类型
-
值类型包括:基本数据类型int系列、float系列、bool、string、数组和结构体

4.2.2 数组
1.介绍
可以存放多个同一类型数据,数组也是一种数据类型,在Go中,数组时值类型。
2.定义
var 数组名 [数组大小] 数据类型


3.遍历
- for-range
for index,value :=range array{}
-
第一个返回值index时数组的下标
-
第二个value是在该下标位置的值
-
可以使用_忽略
4.注意事项和细节
-
数组是多个相同类型数据的组合,一个数组一旦声明/定义了,其长度是固定的,不能动态变化
-
var arr []int 这时arr就是一个slice切片
-
数组中的元素可以是任意类型,不能混用
-
数组创建后,如果没有赋值,有默认值
-
使用数组的步骤
-
声明数组并开辟空间
-
给数组各个元素赋值
-
使用数组
-
数组下标必须在只当范围内使用,否则报panic,数组越界
-
可以使用引用传递(指针方式)修改数值
4.2.3 结构体-golang支持面向对象变成特性
4.2.3.1 面向对象说明
-
没有类,go语言的结构体和其他编程语言的类有同等地位
-
去掉了传统的语言继承、方法重载、构造函数和析构函数、隐藏的this
-
仍然有继承、封装和多态------继承通过匿名字段来实现
-
共中面向接口变成非常重要
4.2.3.2结构与结构体变量的区别
-
结构体是自定义的而数据类型,代表一类事物
-
结构体变量(实例)是具体的额,实际的,代表一个具体变量

4.2.3.3 声明结构体
go
type 结构体名称 struct {
field1 type
field2 type
}
1.基本介绍
-
结构体字段 = 属性 = field
-
字段是结构体的一个组成部分,一般是基本数据类型、数组,也可以是引用类型
2.注意事项和细节
-
字段声明语法同变量
-
在创建一个结构体变量后,如果没有给字段赋值,都对应一个默认值
-
结构体类型是指针、slice和map的默认值都是nil,即没有分配空间。如果需要使用指针,用new,slice和map,需要make。
-
不同结构体变量的字段是独立的,互不影响
4.2.3.4 创建结构体和访问结构体字段
go也支持结构体指针.字段名
-
直接声明var person Person
-
var person Person = Person{}
-
var person *Person = new (Person) ------返回的是结构体指针
-
var person *Person = &Person{}------返回的是结构体指针
go
type Person struct{
Name string
Age int
}
// 方式二:
var person Person = Person{}
p2 := Person{"tom",20}
// 方式三:结构体指针var person *Person = new (Person)
var p3 *Person = new(Person)
// go的设计者为了使用方便,底层会对p3.Name = "tom"及逆行处理
*(p3).Name = "tom" //p3.Name = "tom"
*(p3).Age = 20 //p3.Age = 20
// 方式四:var person *Person = &Person{"tom"20}
var person *Person = &Person{}
(*person).Name = "tom"//person.Name = "tom"
4.2.3.5 使用细节和注意事项
- 结构体的所有字段在内存中是连续的
4.2.4 管道
4.2.5 函数
4.2.5.1 基本介绍
1.定义
为完成某一功能的程序指令的集合。
2.分类
-
自定义函数
-
系统函数
3.基本语法
go
func 函数名 (形参列表) (返回值类型列表) {
执行语句
return 返回值列表
}
-
形参列表:表示函数的输入
-
返回值可有可无
go
package main
import (
"fmt"
)
func cal(n1 float64, n2 float64, operator byte) float64 {
var res float64
switch operator {
case '+':
res = n1 + n2
case '-':
res = n1 - n2
case '*':
res = n1 * n2
case '/':
res = n1 / n2
default:
fmt.Println("操作符错误。。。。")
}
return res
}
func main() {
result := cal(1.2, 2.3, '-')
fmt.Println("result=", result)
}
4.注意事项和细节
-
函数的形参列表可以是多个,返回值列表也可以是多个
-
形参列表和返回值泪飙的数据类型可以是值类型和引用类型
-
函数的命名遵循标识符命名规范
-
函数中的变量是局部的,函数外不生效
-
基本数据类型和数组默认都是值传递,即进行值拷贝。在函数内修改不会影响原来的值
-
如果希望函数内的变量能修改函数外的变量,可以传入变量的地址&,函数内以指针的方式操作变量

-
Go函数不支持重载------函数名相同,形参个数个数和形参类型不同
-
函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量,通过该变量可以对函数调用
-
函数既然是一种数据类型,因此也可以作为形参,相当于调用
-
自定义数据类型
-
基本语法:type 自定义数据类型名 数据类型
-
支持对函数返回值命名
-
支持可变参数------放在形参列表的最后
-
args时slice切片,通过args[index]可以访问到各个值
go
func sum(n1 int,args... int) int {
sum := n1
for i :=0; i<len(args);i++ {
sum += args[i]
}
return sum
}
res := sum(10,3,6)
4.2.5.2 调用机制
4.2.5.2.1 调用过程

说明:
-
再调用一个函数时,会给该函数分配一个新的空间,编译器会通过自身的处理让这个新的空间和其它的栈空间区分开
-
每个函数对应的栈中,数据空间是空间的,不会混淆
-
当一个函数调用完毕,程序会销毁这个函数对应的栈空间
4.2.5.2.2 return语句
1.基本语法
支持返回多个值
go
func 函数名 (形参列表) (返回值类型列表) {
语句...
return 返回值列表
}
-
如果返回多个值时,希望忽略某个返回值,则使用_
-
返回值只有一个,可以不写()
4.2.5.3 递归调用
1.基本介绍
一个函数在函数体内又调用了本身。

2.总结
-
执行一个函数时,就创建一个新的受保护的独立空间(新函数栈)
-
函数的局部变量是独立的,不会相互影响
-
递归必须向退出递归的条件逼近,否则就是无限递归,死递归
-
当一个函数执行完毕,或者遇到return,就会返回,遵守谁第哦啊用,就将结果返回给谁。同事当函数执行完毕或者返回时,该函数本身也会被系统销毁。
4.2.5.4init函数
1.基本介绍
每一个源文件都可以包含一个init函数。该函数会在main函数执行器前,被Go运行框架调用。
2.注意事项和细节
-
如果一个文件同事包含全局变量定义,init函数和main函数,则执行的流程是变量定义-》init函数-》main函数
-
init函数最主要的作用,完成一些初始化工作

4.2.5.5 匿名函数
1.介绍
某个函数只希望使用一次,可以考虑使用匿名函数,匿名函数也可以实现多次使用。
2.使用方式
-
在定义匿名函数时直接使用:只能调用一次。
-
将匿名函数赋给一个变量,再通过该变量来调用匿名函数。
3.全局匿名函数
如果蒋匿名函数赋给一个全局变量,那么这个匿名函数,就成为一个全局匿名函数。
go
package main
var (
Fun = func(n1 int,n2 int) int {
return n1 * n2
}
)
func main(){
rs := Fun(4,9)
}
4.2.5.6 闭包
1.介绍
是一个函数与其他相关的引用环境组合的一个整体。
go
func Add() func (int) int {
// 闭包开始
var n int = 10
return func (x int) int {
n = n + x
return n
}
// 闭包结束
}
f := Add()
f(1) // 11 每调用一次就累加,不会一直初始化
f(2) // 11 + 2 = 13
4.2.5.7 defer
1.介绍
延时机制
go
func sun (n1 int,n2 int) int {
// 当执行到defer时,暂时不执行,会将defer后面的语句压入到独立的栈
// 当函数执行完毕后,再从defer栈中,按照先入后出的方式出栈执行
defer fmt.Println("n1",n1) //3
defer fmt.Println("n2",n2) //2
res := n1 + n2
defer fmt.Println("ok",ok) //1
return res
}
func main(){
res := sum(10,20)
}

2.注意事项
-
当执行到defer时,暂时不执行,会将defer后面的语句压入到独立的栈
-
当函数执行完毕后,再从defer栈中,按照先入后出的方式出栈执行
-
再defer将语句放入到栈时,也会将相关的值拷贝同时入栈
4.2.5.8 参数传递方式
1.基本介绍
值类型参数默认就是值传递。
2.传递方式
-
值传递:值拷贝------传递给函数的都是变量的副本
-
引用传递:传的是地址
地址拷贝效率高,因为数据量小,而值拷贝据欸的那个拷贝的数据大小,数据越大,效率越低。

4.2.5.9变量作用域
1.说明
-
局部变量:函数内部
-
全局变量:函数外部
4.2.5.10内置函数-builtin
- new:用来分配内存,主要用来分配值类型
go
num := new(int)片

- make:用来分配内存,主要用来分配引用类型
4.2.6 切片slice
4.2.6.1 基本语法
var 变量名 []类型
4.2.6.2 长度
切片的长度可以变化,是引用类型。

4.2.6.3 内存中的形式

4.2.6.4使用
-
定义一个切片,然后让切片去引用一个已经创建好的数组。
-
通过make来创建切片
-
基本语法:var 切片名 []type = make([]type,len,[cap]
-
参数说明:
-
type:数据类型
-
len:大小
-
cap:切片容量------大于等于长度
-

-
通过make创建出来的切片对应的数组是由make底层维护,对外不可见。
-
定义一个切片,直接就指定具体数组,使用原理类似make。
4.2.6.5遍历
-
for循环
-
for-range
4.2.6.6注意事项和使用细节
-
切片初始化时,var sice = arr[startIndex:endIndex]-不含结束下标
-
初始化时不能越界------可以动态增长
-
var slice = arr[0:end]------var slice = arr[:end]
-
var slice = arr[start:len(arr)]------var slice = arr[start:]
-
var slice = arr[0:len(arr)]------var slice = arr[:]
-
cap为内置函数,用于统计切片的容量,即最大可以存放多少个元素
-
切片定义完后,还不能使用,因为本身是一个空的,需要让其引用到一个数组,或者make一个空间供切片来使用
-
切片可以继续切片
-
append内置函数,可以对切片进行动态追加

-
切片的拷贝:使用copy内置函数完成
-
copy(slice1,slice2):把slice2拷贝给slice1------只有切片才可以拷贝
-
append顶层原理分析
-
切片append擦欧总的本质就是对数组扩容
-
go地层会创建一下新的数组
-
将slice原来包含的元素拷贝到新的数组
-
slice重新引用到新的数组
-
注意新的数组是在底层来维护的,程序员不可见
-

4.2.6.7字符串string和切片slice
- string是不可变的,通过string[0]修改,会报错------如果需要修改字符串,可以先将string-》[]byte/或者[]rune-》修改-》重写转成string
go
str := "hello"
// 只限定英文/数字
arr := []byte(str)
// 修改中文不会报错
arr := []rune(str)
arr[0] = 'a'
str = string(arr1)
4.2.7接口
4.2.8map
4.2.8.1介绍
是key-value数据结构,又称为字段或者关了数组。
4.2.8.2基本语法
var map变量名 map[keyType]valueType
key的类型:bool、数字、string、指针、channel------通常为int、string
value的类型:数字、string、马坡、struct
go
// 声明了但是未赋值
var a map[string]string
// 在使用map前,需要make分配
a = make(map[string]string, 10)
a["no1"] = "halou"
a["no2"] = "哈哈哈"
a["no3"] = "map"
fmt.Println("a", a)
- map的key-value是无序的
注意:
-
slice、map和function不可以作为key
-
声明后不会分配内存,初始化需要make,分配内存后才能赋值和使用
4.2.8.3使用方式
- 声明---make---赋值
go
// 声明---make---赋值
var a map[string]string
a = make(map[string]string, 10)
a["no1"] = "halou"
a["no2"] = "哈哈哈"
a["no3"] = "map"
fmt.Println("a", a)
- 声明的同时make
go
cities := make(map[string]string)
cities["no1"] = "西安"
cities["no2"] = "长武"
fmt.Println("cities", cities)
- 声明的时候直接赋值
go
heros := map[string]string{
"hero1": "松江",
"hero2": "lusuoyi",
}
fmt.Println("heros", heros)
4.2.8.4增删改查(crud)
- 增加和修改------map["key"] = value//如果没有key。就是增加,否则就是修改
go
cities := make(map[string]string)
cities["no1"] = "西安"
cities["no2"] = "长武"
cities["no3"] = "上海-"
fmt.Println("cities", cities)
// 增加和修改:因为no3已经存在,所以是修改
cities["no3"] = "渭南"
-
删除------delete(map,"key")delete是一个内置函数,如果key村子啊,就删除key-value,如果不存在,就不操作,但是也不会报错。
-
细节说明
-
如果要删除map的所有key,没有一个专门的方法一次删除,可以遍历一下key,诸葛删除
- 或者map = make(...),make一个新的,让原来的成为垃圾,被gc回收
go
// 删除
delete(cities, "no1")
delete(cities, "no5")
// 一次性删除
cities = make(map[string]string)
fmt.Println("cities", cities)
- 查询
go
cities := make(map[string]string)
cities["no1"] = "西安"
cities["no2"] = "长武"
cities["no3"] = "上海-"
val, ok := cities["no2"]
if ok {
fmt.Printf("有no2 key,值为%v", val)
} else {
fmt.Printf("不存在,值为%v", val)
}
4.2.8.5遍历
1.使用for-range遍历
go
cities := make(map[string]string)
cities["no1"] = "西安"
cities["no2"] = "长武"
cities["no3"] = "上海-"
fmt.Println("cities", cities)
fmt.Println("cities有", len(cities) )
for k, v := range cities {
fmt.Printf("k = %v,v= %v\n", k, v)
}
4.2.8.6map切片
1.基本介绍
切片的数据类型如果是map,则我们称为map切片,则map个数就可以动态变化了。


4.2.8.6排序
1.基本介绍
-
没有一个专门的方法针对map的key进行排序
-
map默认是无序的
2.方法:
-
先将map的key放入切片中
-
对切片进行排序
-
遍历切片,然后按照key来输出map的值

4.2.8.7使用细节
-
map是引用类型,遵守引用类型的传递机制,在一个函数接收map,修改后,会直接修改原来的map
-
map的容量打倒后,在想map增加元素,会自动孔融,并不会发生panic,也就是map能动态的增长键值对
-
map的value也经常使用struct类型
4.3值类型和引用类型
1.说明
-
值类型 :基本数据类型int系列、float系列、bool、string、数组和结构体------栈中存储
-
引用类型 :指针、slice切片、map、管道chan、interface------堆中存储
2.使用特点:

5. 标识符的命名规范
1.命名规则
-
大小写字母、0-9、_组成
-
数字不可以开头
-
严格区分大小写
-
标识符不能包含空格
-
下划线_,在go中是一个特殊的标识符,成为空标识符,仅作为占位符使用。
-
不能以系统保留关键作为标识符。
2.注意事项
- 包名:保持package的名字和目录保持一致,尽量采取有意义的包名。

-
变量名、函数名、常量名采用驼峰法。
-
如果变量名、函数名、常量名首字母大写,则可以被其他包访问,如果首字母小写则只能在本包中使用。(首字母大写公由,首字母小写私有)

6. 运算符
注意:没有三元运算符。
6.1 算术运算符
1.分类:

2.使用细节
-
对于除号,它的整数除和小数除有区别:整数之间做除法时,只保留整数部分而舍弃小数部分
-
当对一个数取模时,等价于a%b=a-a/b*b
-
自增自减只能当作一个独立语言使用,不能b :=a++

-
++和--只能卸载变量的后面,不能卸载变量的前面
-
没有自增自减的混淆写法
6.2 赋值运算符

eg:不借助第三个变量,交换两个值
go
var a int = 10
var b int = 20
a= a + b
b = a - b // b=a+b-b=>b=a
a = a - b //a=a+b-a=>a=b
6.3 比较/关系运算符

6.4 逻辑运算符
1.连接多个条件
2.分类:
-
&&(短路与):两边为真,则为真。
-
如果第一个为false,则后续不判断,结果为false
-
||(短路或):一个为true,则为true
-
如果第一个为true,则后续不判断,结果为true
-
!:

6.5 位运算符
-
&(按位与运算符):同1为1,否则为0
-
|(按位或运算符):有一个1结果为1
-
^(按位异或运算符):当二进制位不同时,为1,否则为0
-
<<(左移运算符):
-
>>(右移运算符):

6.6 其它运算符
6.6.1 &
1.返回变量存储地址
6.6.2 *
1.指针变量
6.7 运算符优先级
- 单目运算符、赋值运算符从右向左
6.8 键盘输入语句
1.介绍
需要接收用户输入的数据
2.步骤
-
导入fmt
-
调用fmt包的Scanln/Scanf


7. 流程控制
7.1 顺序控制
7.2 分支控制---if-else
7.2.1 单分支
1.基本语法
go
if 条件表达式 {
执行代码块
}
注意:{}必须要有。
go
// 支持在if中直接定义一个变量
if age :=20; age > 18 {
fmt.Println("你的年龄大于18")
}
7.2.2 双分支
7.2.3 多分支
7.2.3.1 嵌套分支
1.嵌套分支不宜过多。
7.2.3.2switch分支
1.基本介绍
-
每一个case分支都是唯一的,从上到下逐一测试
-
匹配项后面不需要再加break
2.基本语法:
go
switch 表达式 {
case 表达式1,表达式2,...:
语句块1
case 表达式3,表达式4,...:
语句块1
case 表达式5,表达式6,...:
语句块1
default:
语句块
}
3.使用细节
-
case后是一个表达式
-
case后的各个表达式的值的数据类型必须和switch的表达式数据类型一致
-
case后面可以带多个表达式,使用都好间隔
-
case后表达式如果是常量值,则要求不能重复
-
case后不需要break
-
default语句不是必须的
-
switch后也可不带表达式
-
switch后也可直接声明/定义一个变量,分号结束------不推荐
-
switch穿透-fallthrough,如果在case语句块后增加fallthrough,则会继续执行下一个case,也叫switch穿透
-
Type switch:switch语句还可以被用于type-switch来判断某个interface变量中实际指向的变量类型

7.3 循环控制
注意:go语言中没有while和do while
7.3.1 for循环
go
for i := 1; i <=10;i++{
fmt.Println("halou")
}
1.使用细节
-
循环条件返回是一个bool值
-
for循环第三种使用方式:将变量初始化和变量迭代写到其他位置
go
for 循环判断条件 {
// 循环执行语句
}
j := 1
for j<=10 {
j++ //循环变量迭代
}
- for循环第三种使用方式:
go
for {
// 循环执行语句
}
// 等价于for;;{}是一个无限循环,通常需要配合break语句使用。
看:= 1
for { //for;;{}
if k <=10 {
fmt.Println(""ok)
} else {
break //跳出整个for循环
}
k++
}
- for-range:可以方便遍历字符串和数字
go
var str string = "hello world!大家后"
// 传统的字符串遍历 如果字符串中有中文就会报错
// for i := 0; i < len(str); i++ {
// fmt.Printf("%c \n", str[i])
// }
str2 := []rune(str)
for i := 0; i < len(str2); i++ {
fmt.Printf("%c \n", str2[i])
}
var str string = "hello world!"
for index, val := range str {
fmt.Printf("index= %d,val=%c \n", index, val)
}
注意:for-range遍历字符串时,是按照字符来遍历的,而不是按照字节来的。

7.3.2 while和do...while实现
7.3.2.1 while
go
for {
if 循环条件表达式 {
brak //跳出for循环
}
// 循环遍历操作语句
// 循环变量迭代
}
7.3.2.1 do...while
go
for {
// 循环遍历操作语句
// 循环变量迭代
if 循环条件表达式 {
brak //跳出for循环
}
}
7.4 跳转控制语句
7.4.1 break
eg:生成随机数
go
rand.Seed(time.Now().UnixNano())
n := rand.Intn(100) + 1
1.基本介绍
用于终止某个语句块的执行,用于中断当前for循环或跳出switch语句。
2.基本语法
go
{
...
breavk
}
3.使用细节
- break出现在多层嵌套的语句块中时,可以通过标签指明要种植的是那一层语句块

7.4.2 continue
1.接本介绍
-
结束本次循环,继续执行下一次循环。
-
出现在多层嵌套语句体中时,可以通过标签指明要跳过的时那一层循环。
7.4.3 goto
1.介绍
-
可以无条件地转移到程序中指定的行
-
通常与语句配合使用,可以实现条件转移,跳出循环体等
-
注意:一般不主张使用goto语句
2.基本语法
go
goto label
...
label: statement
7.4.4 return
1.介绍
使用在方法或函数中,表示跳出所在的函数或方法。
8. 包
8.1 原理
包的本质就是创建不同的文件夹,来存放程序文件。
8.2 介绍
1.概念
go的每一个文件都属于一个包,go是以包的形式来管理文件和项目结构。
2.三大作用
-
区分相同名字的函数、变量等标识符
-
方便管理项目
-
控制函数、变量等访问范围,即作用域
3.相关说明
-
打包基本语法:
-
package 包名(文件夹名)
-
引入包的基本语法:
-
import "包的路径"
4.使用细节
-
在给一个文件打包时,该包对应一个文件夹。包名通常跟所在文件名相同
-
package打包指令在文件第一行,然后是import
-
import引入包时从$GOPATH的src下开始,不用带src,编译器会自动从src下开始
-
跨包访问需要首字母大写
-
访问呢其他包函数时,语法时包名.函数名
-
如果包名较长,go支持取别名,使用别名访问
go
import (
my "goCode/day02/testImport/myMath"
)
-
在同一包下,不能有相同的函数名,否则报重复定义
-
如果要编译成可执行程序文件,需要将这个包声明为main
-
go build 需要打包的文件路径

9. 错误处理机制
1.处理方式:defer、panic、recover
Go抛出一个panic的异常,然后再defer中通过recover捕获这个异常,然后正常处理。

2.自定义错误
-
errors.New("错误说明"),会返回一个error类型的值,表示一个错误
-
panic内置函数,接受一个interface{}类型的值作为参数,可以接收error类型的变量,输出错误信息,并退出程序。
