Day1 Go基础语法 | 青训营笔记

99 阅读8分钟

Go语言基础

参考内容:betytech、runoob

开发环境搭建

前面几个大佬的教程都非常给力

学生认证真好用(bushi

什么是Go语言

  1. 高性能高并发
  2. 语法简单易懂,类似C语言,且在C上进行大幅度简化,学习曲线平缓。
  3. 丰富标准库,完善的工具链
  4. 所有的编译结果默认为静态链接,只需要拷贝编译后的唯一可执行文件即可运行
  5. 静态语言里几乎最快的编译速度
  6. 跨平台
  7. 附带垃圾回收,无需在意内存释放。
  8. 性能较好,部署简单,学习成本低。

环境配置

安装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了)

变量

全局:函数体外声明。

局部:函数体内声明,作用域为函数体内,而函数的参数,返回值均为局部变量。

类型:
  1. 布尔值 bool true or false(默认是false)
  2. 数字类型 整数型:(u)int(bits) 浮点型:float(bits) complex(bits)...etc 对于数字类型,无需定义int与float(系统自动识别)
  3. 字符串类型(UTF-8编码标识的Unicode文本)内置类型,可直接拼接(但还是个结构体,其包含一个指向底层数据的指针和一个表示字符串长度的整数。
  4. 派生类型

对于上述中的基本类型都属于值类型,其变量直接指向内存中的值

而=的使用,是在内存中奖其值进行了拷贝:值有多份;同样,我们可以对变量使用&/*符号获取其内部地址(指针)而当对指针类型使用=,则将其地址拷贝,使得二者指向同一值。

声明:

一般使用var关键字: var name1, name2

也可以使用赋值操作符:“:=”(反正变量初始化时可以省略其类型让系统去推,直接用:=还能少写var,并且,并行赋值(相当于一个函数返回多个值)还能节约行数(bushi

Ps:对同一个变量而言,var与:=不能都用上:初始化只能有一次,且声明了就必须用上

  1. 指定变量类型,但没有初始化:默认零值(初始值)
  2. 由值自行判断变量类型
常量

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:函数可以有多个返回值

用法:

  1. 函数作为实参数
  2. 闭包 (内联)
  3. 方法 包含了接受者:命名类型/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)