Go语言基础
参考内容:betytech、runoob
开发环境搭建
前面几个大佬的教程都非常给力
学生认证真好用(bushi
什么是Go语言
- 高性能高并发
- 语法简单易懂,类似C语言,且在C上进行大幅度简化,学习曲线平缓。
- 丰富标准库,完善的工具链
- 所有的编译结果默认为静态链接,只需要拷贝编译后的唯一可执行文件即可运行
- 静态语言里几乎最快的编译速度
- 跨平台
- 附带垃圾回收,无需在意内存释放。
- 性能较好,部署简单,学习成本低。
环境配置
安装Golang及其编辑器/IDE vscode(编辑器) / Goland 执行:go run 文件名.go 还可以使用go build来生成二进制文件
基础语法
语言结构
以最经典的Hello World来举例:
package main
//此处定义了包名,指明该文件属于哪个包
//package名与文件名关系不大,且没有直接联系,单但同一文件夹下的文件只能有一个包名
import "fmt"
//需要fmt包,其中,fmt包实现了格式化IO函数
func main(){
//注意,'{'不能单独在一行(还好符合代码习惯)
//经典的main函数起手,不过如果有init()函数则优先init()
fmt.Println("Hello, world!")
}
Ps:当标识符以一个大写字母开头时,那么使用该标识符的对象就可以被外部包的代码所使用(前提是import了)
变量
全局:函数体外声明。
局部:函数体内声明,作用域为函数体内,而函数的参数,返回值均为局部变量。
类型:
- 布尔值 bool true or false(默认是false)
- 数字类型 整数型:(u)int(bits) 浮点型:float(bits) complex(bits)...etc 对于数字类型,无需定义int与float(系统自动识别)
- 字符串类型(UTF-8编码标识的Unicode文本)内置类型,可直接拼接(但还是个结构体,其包含一个指向底层数据的指针和一个表示字符串长度的整数。
- 派生类型
对于上述中的基本类型都属于值类型,其变量直接指向内存中的值
而=的使用,是在内存中奖其值进行了拷贝:值有多份;同样,我们可以对变量使用&/*符号获取其内部地址(指针)而当对指针类型使用=,则将其地址拷贝,使得二者指向同一值。
声明:
一般使用var关键字: var name1, name2
也可以使用赋值操作符:“:=”(反正变量初始化时可以省略其类型让系统去推,直接用:=还能少写var,并且,并行赋值(相当于一个函数返回多个值)还能节约行数(bushi
Ps:对同一个变量而言,var与:=不能都用上:初始化只能有一次,且声明了就必须用上
- 指定变量类型,但没有初始化:默认零值(初始值)
- 由值自行判断变量类型
常量
const标识符: 还可以用来枚举。const值可以使用len(), cap()等函数。
iotas:特殊常量:可以被编译器修改。在新一行被使用时++。
运算符
和C/C++相同/相似,直接跳过
条件:
if else
不同点:if后方没有括号。
几个if语句不能塞在同一行。
switch case
相比于C++,其不需要break即可在对应条件下直接结束,不会去跑其他的分支。
相比于C++功能更加强大,比较的变量可以是任意的,swicth后可以不加任何变量,而在case里直接写条件分支。
type-switch:switch 变量名.(type) 来判断变量的变量值类型并选择分支。
在case语句中,使用fallthrough将强制执行后续的case语句。
多条件匹配,default的永久最后执行
循环:
循环只有for循环,但这个for循环像是C中for,while的集成。
continue继续,break跳出循环,goto......能不用就不用。
数组:
易于读取特定索引下的值 && 唯一已编号且长度固定的数据向序列。
声明:var variable_name [SIZE] variable_type。
初始化:使用{}多次初始化。
不像python支持负数索引--》老老实实算索引。
切片:slice
灵活而功能强悍的内置类型切片(“动态数组”)
切片:原理:存储长度加容量+指向数组指针,如果容量不够,则扩容并返回一个新的slice(一般扩充2倍),因此需要赋值回去。
struct slice{
bytes* array;
uintgo len;
uintgo cap;
}
声明:var identifier [type] 初始化:
s := [] int {1, 2, 3}
// 此处直接初始化切片,其中[]表示切片类型, {1,2,3}初始化值依次为1,2,3,其cap=len=3
s := arr[:]
// 初始化切片为数组arr的引用
len(): 长度获取。
cap(): 切片容量获取。
copy(dst, src):拷贝数值。
append追加元素:将append的结果复赋值回原切片。
切片截取:利用 [ ] 设置上下限来截取切片。
空切片:nil(未初始化之前默认为nil,长度为0)
Map:
键值对/字典/集合,完全无序。
用key来快速检索数据,key类似于索引,其指向数据的值。
可以利用make创建一个空map:如make(mapp[string]int),利用方括号语法可以向其中写入key_read,也可以通过方括号读取。
//内建函数make
map_variable := make(map[KeyType], initialCapacity)
// 使用字面量创建Map
m := map[string]int(
"apple": 1,
"banana": 2,
)
delete()函数: 删除集合的元素,参数为map何和其对应的key。
在从map中读取key_read对时,可以在后方加入参数ok来判断该key_read对是否存在
Range:
for循环中迭代数组(arr),切片(slice),通道(channel),集合(map),如
for key, value = range oldMap {
newMap[key] = value
}
但是注意:Go语言的字符类型使用的是UTF-8编码,在逐个遍历字符是必须采用==for-each==形式
for variable_type variable : range map{
}
函数func
func function_name( [parameter list] ) [return] {
}
Ps:函数可以有多个返回值
用法:
- 函数作为实参数
- 闭包 (内联)
- 方法 包含了接受者:命名类型/struct 在函数定义中函数名前加上(接受者类型, 参数名)
指针:
差不多的感觉......
对于函数中传入的值修改其本身(引用传递)
结构体:
带类型的字符的集合
type strcut_variable_type struct {
member definition
member definition
//etc
}
初始化需要传入每个字段的初始值,未初始化则为空值。
用. 来访问结构体中的值: struct 变量.成员 or struct 指针.成员
可以作为函数的参数传入
结构体方法 类似于其他语言中的类成员函数
结构体中,首字母大写相当于==public==,小写相当于==private==(这个public/private是相当于对package而言)
而将结构体转为JSON时,其首字母必须大写才能正常转换。其可以利用json.Marsha(相同变量对应的struct)进行序列化,JSON将被其转为一个bat数组(近似字符串。不过print的时候需要转换)
Print:%#v 最详细的方式打印出
接口:
将具有共性的方法定义在一起,通过接口,可以讲不通同的类型绑定在一组公用的方法上。->实现多态
隐式实现,一个类型实现了该接口定义的所有方法->自动实现了该接口。
// 接口定义
type interface_name interface {
//interface的本质是一个执指针
method_name1 [return_type]
...
}
// 实现用的结构体
type struct_name struct{
}
// method
func (struct_name_variable struct_name) mehod_name1() [return_type] {
//方法实现
}
像是class啊。
错误处理err:
一个接口类型
type error inierface {
Error() strng
}
在编码中,清晰得到是哪个函数返回的错误,并返回错误信息。可以用简单if,else来进行处理。 panic: 主动抛出错误,由函数主动调用/程序运行时产生错误,由运行时检测并退出。 发生panic后,程序从发生panic的位置直接返回,逐层向上执行函数的defer语句(向外扩散),然后逐层打印函数调用堆栈,直到被recover捕获/到达最外层。 recover:捕获panic抛出的错误。recover与defer一起使用,但是defer只有在后面的函数体内直接被调用才能捕获panic来终止异常。(defer需要在panic前声明)
时间处理:
此处参考了稀土掘金中的文章《详解Go time包时间处理》作者:劲仔Go
time.LoadLocation() 时区设置:依赖当前的时区数据库
time.UTC() / time.Local() 快速进行时区切换
time.Date() 构筑一个带时区的时间
time.Now() 获取现在时间 .Unix() 秒 .UnixNano() 毫秒 ...
可以用.Year(),.Month()得到time中的值
格式化的时候使用用特定时间:2006-01-02 15:04:05 如:time.Format("2006-01-02 15:04:05.000")
time.ParseInLocation() 指定时区解析指定时间,并获取时间对象
time.Duration() 获取两个时间点之间经过的时间,以纳秒为单位。
time.Tick(时间间隔) 进行定时器设置(本质上是一个channel)