GO语言快速上手-基础语法大全|青训营笔记

341 阅读14分钟

GO语言快速上手-基础语法大全|青训营笔记

这是我参与「第三届青训营 -后端场」笔记创作活动的的第一篇笔记

一.go语言的特点 1.高性能、高并发 2.语法简单、学习曲线平缓 3.丰富的标准库 4.完善的工具链 5.静态链接 6.快速编译 7.跨平台 8.垃圾回收

二.基础语法

2.1 package //参考文章《Go语言--包(Package)》 blog.csdn.net/u010429831/… Go语言继承了命名空间的概念,采用包来组织代码,包名构成Go命名空间的一部分,不同的包就是一个独立的命名空间。Go语言除了包级显式的命名空间,还有隐式的命名空间。函数、方法,以及 if、for、switch 等和 “{ }” 一起构成了一个个代码块,代码块可以嵌套代码块,每一个代码块都构成一个隐式的命名空间。不同命名空间可以声明相同的标识符,所以不同的隐式的命名空间同样允许声明相同的标识符(包括变量)。

2.1.1作用域 在高级编程语言中,作用域(scope)是指名字(name)与实体(可以理解为特定内存地址)的绑定(binding)保持有效的那部分程序逻辑区间。Go语言是静态作用域的编程语言。所谓静态作用域就是变量的作用域不依赖程序执行时的因素,变量作用域在编译器就能确定。

Go语言有三种类型的作用域:

全局作用域 在任何地方都可以访问的标识符,称其具有全局作用域。在Go语言中,全局作用域有两类:

(1)Go语言内置的预声明标识符(包括预声明的类型名、关键字、内置函数等),它们具有全局作用域,在任意命名空间内都可见。

(2)Go语言包内以大写字母开头的标识符(包括变量、常量、函数和方法名、自定义类型、结构体字段等),它们具有全局作用域,在任意命名空间内都可见。(这也就是为什么平时使用官方包给出的函数时,开头都为大写。)

包内作用域 在Go语言包内以小写字母开头的标识符(包括变量、常量、函数和方法名、自定义类型、结构体字段等),它们在本包可见,在其他包都是不可见的,这些标识符具有包内作用域。

隐式作用域 每个代码块内定义的变量称为“局部变量”,这些局部变量只在当前代码块内可见,其作用域属于当前代码块的隐式作用域。(分配给程序栈管理的变量)

2.1.2 包的基本概念 Go语言的源码复用是建立在包(package)基础之上。Go语言的入库 main() 函数所在的包(package)叫 main 包,main包想要引用别的代码,必须同样以包的方式进行引用。Go语言使用包来组织代码的,并实现命名空间的管理。任何源代码文件必须属于某个包。源码文件的第一行有效代码必须是 package pkgName 语句,通过该语句声明自己所在的包。

Go语言的包借助了目录树的组织形式,一般包的名称就是其源文件所在目录的名称,虽然Go没有强制包名必须和其所在的目录名同名,但还是建议包名和所在目录同名,这样结构更清晰。包可以定义在很深的目录中,包的定义是不包括路径的,但是包的引用一般是全路径引用。比如在 $GOPATH/src/a/b 下定义一个包 c,在包 c 的源码中只需要声明为 package c,而不是声明为 package a/b/c,但是在 import 包 c 时,需要带上路径 import a/b/c。

包的习惯用法:

包名一般是小写的,使用一个简短的命名。 包名一般要和所在目录名同名。 包一般放在公司的域名目录下,这样能保证包名的唯一性,便于共享代码。比如个人的GitHub项目的包一般放到 $GOPATH/src/github.com/userName/projectName 目录下。(gopath详见文章)

2.2 变量 参考《Go语言之变量》blog.csdn.net/LesuperV/ar… go语言是一门强类型语言,每一个变量都有它自己的变量类型。 大部分运算符的使用和优先级与c或c++类似。 字符串是内置类型,可以直接通过加号拼接,也可以用等于逻辑运算去进行比较。 2.2.1变量常见的声明方式 1. 变量声明的格式为:var identifier type,也就是需要使用到关键字var,在Go语言中声明变量时将变量的类型放在变量的名称后面,这与其他语言不同。

//定义一个变量为int型
var a int
// 定义一个变量为bool型
var b bool
// 定义一个变量为string型
var str string
// 定义两个变量为int型
var a,b int

也可按如下方法声明以及赋初值

var (
	a,b int
	c	bool
	str string
)
// 同一类型的多个变量可以声明在同一行
var a,b,c int
// 多变量可以在同一行进行声明和赋值
var a,b,c int = 1,2,3

上面的声明方式都称为静态声明,除此之外,Go语言还有动态声明方式,该声明方式与常量声明一样:

var a,b,c = "string",1,true

在这种动态声明中,变量可以拥有不同的类型,Go语言编译器会自动推断 2. 变量的声明有两种写法,上面是一种,另一种就是:=赋值运算符号代替,就像这样:

a := 1
// 等同于 var a = 1

此处也不指定变量类型也是因为Go语言编译器也会自动判断变量类型
Go语言官方推荐使用这种方式来声明变量,但是必须注意,这样的声明方式只能在函数体内,不可以用在全局变量声明与赋值。 使用 := 可以快速创建一个函数内部的变量,它包括初始化声明与赋值两大部分,使用这种方式声明变量需要注意以下几点:

同一个代码块内不能多次声明同一个变量
函数内部可以使用全局定义的变量,意思是可以给变量赋予一个新的值
函数体内属于独立的代码块,可以再次声明全局中定义的变量,可以改变变量的类型,并且定义只在函数内部生效(即局部变量覆盖了全局变量)
函数体内如果在变量定义之前就调用该变量,那么就会编译错误
全局定义的变量不限定位置,但建议统一放在函数代码之前,这样可以提高代码的可读性

2.3 if else参考 blog.csdn.net/can3981132/… 1.if语句

Go语言的条件语句和C++的很像,使用关键词if。 其格式如下:

if 表达式为true {

执行语句

}

和C++的区别是条件表达式不需要用括号括起来 2. if  else语句

当if后的条件为false时则执行else后的语句 if 表达式为true {

执行语句

}else{ 执行语句 } 3.else if语句 else if接在if语句之后(或else if)继续判断以上条件不满足时的其他条件. if 表达式为true {

执行语句

}else if{ 执行语句 } 总体来说除了判断条件的小括号不用写以外(写了也能运行),其他和C++的是一样的。

2.4循环 在go里面没有while 循环、do while 循环,只有唯一的一种 for循环。最简单的for循环就是在for后面什么都不写,代表一个死循环。循环途中你可以用break跳出,也可以使用经典的C循环,就是forl等于0, 1小于NI加加。这中间三段,任何一段都可以省略。在循环里面,你可以用break或者 continue未跳出或者逛续循环。基本与经典c语言差别不大。

2.5 switch go语言里面的switch分支结构。看起来也C或者C++比较类似。同样的在switch后面的那个变量名,并不是要括号。这里有个很大的一点不同的是,在c++里面,switch case如果不不显示加break的话会然后会继续往下跑完所有的case,在go语言里面的话是不需要加break的。相比C或者C++,go语言里面的switch功能更强大。可以使用任意的变量类型,甚至可以用来取代任意的if else 语句。你可以在switch后面不加任何的变量,然后在case里面写条件分支。这样代码相比你用多个if else代码逻辑会更为清晰。

image.png

2.6数组 数组就是一个具有编号且长度固定的元素序列。对于一个数组,可以很方便地取特定索引的值或者往特定素引取存储值,然后也能够直接去打印一个数组。不过,在真实业务代码里面,我们很少直接使用数组,因为它长度是固定的,我们用的更多的是切片。

2.7切片 参考《Go语言--切片(Slice)详解》 blog.csdn.net/qq_45163122… blog.csdn.net/weixin_4339… Go 语言切片是对数组的抽象。

Go 数组的长度不可改变,在特定场景中这样的结构就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。 2.7.1切片的定义 1.声明一个未指定大小的数组来定义切片

var identifier []type
//例如
var slice []int

这会产生一个nil切片,nil 切片是很常见的创建切片的方法,Go不会为nil切片分配任何空间。 2、使用make()函数来创建切片

var slice1 []type = make([]type, len)
//也可以简写为
slice1 := make([]type, len)
//例如
slice := make([]type, len)

当使用make函数且给定长度为0时,如:slice := make([]int, 0),会建立一个空切片,在Go里,空切片在底层数组包含 0个元素,也没有分配任何存储空间。 如果只指定长度,那么切片的容量和长度相等。也可以分别指定长度和容量:

// 创建一个整型切片
// 其长度为 3 个元素,容量为 5 个元素 
slice := make([]int, 3, 5)

分别指定长度和容量时,创建的切片,底层数组的长度是指定的容量,但是初始化后并不能访问所有的数组元素。切片可以访问 3 个元素,而底层数组拥有 5 个元素。剩余的 2 个元素可以在后期操作中合并到切片,可以通过切片访问这些元素。如果基于这个切片创建新的切片,新切片会和原有切片共享底层数组,也能通过后期操作来访问多余容量的元素。 不管是使用 nil 切片还是空切片,对其调用内置函数append、len 和 cap 的返回结果都是一样的。(len和cap都为0) 2.7.2切片的内置函数 1.len() 和 cap() 函数 可以由 len() 方法获取长度。(编程者定义的切片内容的长度) 切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少(即在内存中为该切片分了多少个存储单元) 2.append函数 使用append来追加元素,注意append的用法的话,必须把 append的结果赋值为原数组。因为slice的原理实际上是它有一个它存储了一个长度和一个容量,加一个指向一个数组的指针,在你执行append操作的时候,如果容量不够的话,会扩容并且返回新的slice.slice此初始化的时候也可以指定长度。 slice可以截取切片:如s[2:5]表示的就是第3个元素到第5个元素

2.8 map结构 参考:《【搞定Go语言】第2天7:Go语言基础之map》 blog.csdn.net/qq_33591055… Go语言中提供的映射关系容器为map,其内部使用散列表(hash)实现。Go语言中的map是引用类型,必须初始化才能使用。 Go语言中 map的定义语法如下:

map[KeyType]ValueType
KeyType:表示键的类型。
ValueType:表示键对应的值的类型。

于是可以建立一个keytype和valuetype的哈希表。 map类型的变量默认初始值为nil,需要使用make()函数来分配内存。语法为:

make(map[KeyType]ValueType, [cap])

其中cap表示map的容量,该参数不是必须的。 可以用delete从里面删除键值对。 golang的map是完全无序的,追历的时候不会按照字母顺序,也不会按照插入顺序输出,而是随机顺序。

2.9 range函数 Go语言中的range关键字使用起来非常的方便,它允许你遍历某个slice或者map,并通过两个参数(index和value),分别获取到slice或者map中某个元素所在的index以及其值。 用法如下:

for index, value := range mySlice {
fmt.Println("index: " + index)
fmt.Println("value: " + value)
} 如果不许要索引或者结果的话,可以用下划线来忽略。如: for -, value := range mySlice

2.10函数 golang函数的返回类型是后置的,同时支持多个返回值,使用中常常使用两个返回值,其一为结果,另一个为错误信息。 如: func add(a int, b int) (c int, ok bool)

2.11指针 参考: blog.csdn.net/weixin_4405… go语言也支持指针,但是功能相对来说十分有限。GO语言中会允许这个指针类型对数据进行读写,在传递数据时可以直接使用指针,不用拷贝数据。但是GO语言中的类型指针是不能进行偏移和运算的,根据地址直接获取到整体的数据块。例如数组指针就是直接获取到整个数组信息,而不像c语言中通过偏移或运算来取到具体的元素数据。 具体用法如下

  1. 指针的使用方法

&用来取出地址,用来根据地址取出地址指向的数据值。实际上,指针变量的值就是指针地址,对变量进行&操作可以获取到变量的地址,这个地址也就是指针变量。对指针变量进行 操作时,可以获取到指针变量指向的原变量的值。(用于函数改变参数的值) 2. new()函数

new(Type)函数:只接受一个参数类型。 Type表示类型指针,new()返回一个类型的指针,其对应的值就是这种类型Type的零值。 3. make()函数

make()函数用作内存分配,但它只用于切片、map和channel的内存创建,它所返回的类型就是这三个类型本身,这三个类型其实就是引用类型,可以看作为指针。通过make()函数来为他们进行初始化。

2.12结构体及其方法 1.结构体的话是带类型的字段的集合。比如这里user结构包含了两个字段,name和password.我们可以用结构体的名称去初始化一个结构体变量,构造的时候需要传入每个字段的初始值。也可以用这种键值对的方式去指定初始值,这样可以只对一部分字段进行初始化。同样的结构体我们也能支持指针,这样能够实现对于结构体的修改,也可以在某些情况下避免一些大结构体的拷贝开销。 格式: type user struct{ name string password string } 2.在go语言中不支持类,但是在Golang里面可以为结构体去定义一些方法。会有一点类似其他语言里面的类成员函数。 格式如下: func (u user)check(password string)bool{ return u.password==password } 这样就从一个普通函数,改成了结构体方法。 用户可以像 a.checkPassword("xx)这样去调用。 同时还有一种带指针的结构体写法: func (u user)check(password string)bool{ return u.password==password } 这个它们的区别的话是说如果你带指针的话,那你那么你就可以对这个结构体去做修改。如果你不带指针的话,那你实际上操作的是一个拷贝,你就无法对结构体进行修改。

2.13错误处理 错误处理在go语言里面符合语言习惯的做法就是使用一个单独的返回值来传递错误信息。在函数里面,我们可以在那个函数的返回值类型里面,后面加一个error,就代表这个函数可能会返回错误。那么在函数实现的时候,return需要同时retum两个值,要么就是如果出现错误的话,那么可以retum nil和一个error.如果没有的话,那么返回原本的结果和nil 如:func add(a int, b int) (c int, err error)

剩余知识点 字符串操作 字符串格式化输出 json处理 时间处理 数字解析 对应的包:strings fmt encoding/json time strconv自行查阅即可