Golang基础笔记

《基础》

Go语言中的3个关键字用于标准的错误处理流程: defer,panic,recover。
定义一个名为f 的匿名函数:
Go 不支持继承和重载。
Go的goroutine概念:使得并发编程变得非常简单。
Go语言的 main() 函数不能带参数,也不能定义返回值。所有Go函数以关键字func 开头。
Go支持多个返回值,以上函数返回了两个值(result、err)。并不是所有的返回值都必须赋值。
go version 查看版本信息。运行go程序(编译、链接、运行,3个步骤合并为一步): go run hello.go
如果只生成编译结果而不自动运行,使用: go build hello.go
6g 和 6l 是64位版本的Go编译器和链接器,对应32位的是 8g 和 8l.
打印输出:fmt.Println(123)
终止程序:os.Exit(123)
打印数据结构:
spew.Dump(string(buf)) //类似于PHP的var_dump
spew.Dump(adxRequest)
data := fmt.Sprintf("%f", 33.3) //小数转换为字符串 %f
data := fmt.Sprintf("%d", 28) //整数转换为字符串 %d
data := fmt.Sprintf("%v", 33.3) //小数或者整数都通用 %v
sW := uint32(apiReq.ScreenWidth) //int32转换为uint32
字符串转换为float:
lat, _ := strconv.ParseFloat(apiReq.Lat, 32)
fmt.Println(lat) //float64
fmt.Println(float32(lat)) //float32
 
《变量》
1.使用var声明变量,不需要使用分号作为结束符。
var v1 int
var v2 string
var v3 [10]int //数组
var v4 []int //数组切片
var v6 *int //指针
var v7 map[string]int //map,key 为string类型,value为int类型
var v8 func(a int) int
var v5 struct{
f int
}
可以将多个需要声明的变量放置在一起:
var (
v1 int
v2 string
)
 
2.变量初始化,var关键字可以保留,但不再是必要的元素。以下三种用法的效果完全一样。
var v1 int = 10
var v2 = 10
v3 := 10 // := 明确表达同时进行变量声明和初始化的工作
注意:出现在:= 左侧的变量不应该是已经被声明过得,否则会导致编译错误。
 
3.变量赋值——和变量初始化时两个不同的概念。
var v1 int
v1 = 123
可以多重赋值,如下案例表示交换i和j变量:
i,j = j,i
 
4.匿名变量:
func GetName()(firstName,lastName,nickName string){
return “aaa” , ”bbb” , ”ccc”
}
若只获取nickName,如下调用:_,_,nickName := GetName()
 
《常量》
1.字面常量(literal)—— 程序中硬编码的常量。
2.使用 const 关键字定义常量:
3.预定义常量—— true、false、iota。
 
《类型》
1.布尔 —— 布尔类型不能接受其他类型的赋值,不支持自动或强制的类型转换。
var v1 bool
v1 = true
v2 := (1 == 2)
2. 整型 —— Go中, int 和 int32是两种不同的类型。
3. 浮点型 —— float32 和 float64
4. 复数 —— 实部(real) 与 虚部(imag)
5. 字符串(01.go):
var str string //声明一个字符串变量
str = “Hello world” //字符串赋值
ch := str[0] //获取字符串的第一个字符
fmt.Printf(len(str))
字符串操作:
x + y:连接字符串,”Hello”+”123” ====> Hello123
len(s):获取字符串长度, len(“Hello”) ===> 5
s[i]:获取某个字符,”Hello”[1] ===> ‘e’
字符类型:byte(代表UTF-8字符串的单个字节的值)和rune(代表单个Unicode字符)
 
《数组》
1.数组的声明方法:
[32]byte //长度为32长度数组,每个元素为一个字节
[2*N] struct {x,y int32 } //复杂类型数组
[1000]*float64 //指针数组
[3][5]int //二维数组
[2][2][2]float64//等同于: [2]([2]([2]float64))
2. Go语言中,数组长度在定义后就不可更改。使用len() 获取数组长度:arrLength := len(arr)
3. 遍历整型数组(下标从0开始,len(array)-1 是最后一个元素的下标 )(04.go):
也可以使用 range 关键字便捷地遍历容器中的元素,运行结果同上!(05.go):
4. Go语言中,数组是一个值类型(value type),所有的值类型变量在赋值和作为参数传递时都将产生一次复制动作。(06.go)
----> 可以得出结论:函数modify()内操作的数组 和 main() 中传入的数组是两个不同的实例。
总结数组的特点:长度在定义后无法再次修改;数组是值类型,每次传递都将产生一份副本。
 
《数组切片》
数组切片(slice)拥有自己的数据结构,不仅仅是个指针。
1. 创建数组切片,方法1:基于已存在的数组。(07_slice.go)
用法: myArray[first:last],例如:
mySlice = myArray[:] //基于数组的所有元素创建数组切片
mySlice = myArray[:5] //基于数组的前5个元素创建数组切片
mySlice = myArray[5:] //直接从第5个元素开始的所有元素创建数组切片
2. 创建数组切片,方法2:直接创建—— 使用内置函数make()。
mySlice1 := make([]int,5) //创建一个初始元素个数为5的数组切片,元素初始值为0
mySlice2 := make([]int,5,10) //创建一个初始元素个数为5的数组切片,元素初始值为0,并预留10个元素的存储空间
mySlice3 := []int{1,2,3,4,5} //直接创建并初始化包含5个元素的数组切片
3. 数组切片元素遍历,参考操作数组的方法。len()获取元素个数,支持使用range关键字快速遍历所有元素。
4. 动态增减元素——数组切片比数组更为强大的功能!
内置的cap() 函数:返回数组切片分配的空间大小;len():返回数组切片中当前存储的元素个数。
给已包含元素的数组切片后面继续新增元素,使用append()函数.(08_slice2.go)
5. 基于数组切片创建数组切片
oldSlice := []int{1,2,3,4,5}
newSlice := oldSlice[:3] //基于oldSlice的前3个元素构建新数组切片
说明:newSlice的元素范围可以超过oldSlice,但不能超出old的存储能力(cap()值)
比如new := old[:6],基于old的前6个元素创建,后面补0.
6. 内容复制 —— copy()函数,将内容从一个数组切片复制到另一个数组切片。
 
《map》
map是一堆键值对的未排序集合,
1. 变量声明
var myMap map[string] PersonInfo //string是键的类型,PersonInfo是值的类型。
2. 创建——使用make()创建:
myMap = make(map[string] PersonInfo) //创建一个键类型为string,值类型为PersonInfo的map。
myMap = make(map[string] PersonInfo,100) //创建一个初始存储能力为100的map。
创建并初始化map:
myMap = map[string] PersonInfo{
“1234”: PersonInfo{“1”,”Jack”,”Room 101,...”}
}
3. 元素赋值——将键和值用下面的方式对应起来:
myMap[“1234”] = PersonInfo{“1”,”Jack”,”Room 101,...”}
4. 元素删除—— delete()函数,用于删除容器内的元素:
delete(myMap,”1234”)
如果传入的map变量的值是nil,则会抛出异常(panic)。
5. 元素查找——判断能否从map中获取一个值的做法:
 
《流程控制和函数》
条件判断 if 语句(01_if.go)
选择语句 switch...case (02_switch.go)
循环语句 for (03_for.go)
Go语言中只支持for循环,不支持 while 和 do...while循环。
goto语句 —— 跳转到本函数内的某个标签.(04_goto.go)
 
《函数》
函数的基本组成:关键字func、函数名、参数列表、返回值、函数体、返回语句。(05_fun.go)
函数调用:小写字母开头的函数只在本包内可见,大写字母开头的函数才能被其他包使用。
不定参数 —— 函数传入的参数个数为不定数量(06_func_type.go)。
任意类型的不定参数 ...interface()
多返回值,比如:File.Read()函数可以同时返回读取的字节数和错误信息。
匿名函数 ——不需要定义函数名,由不带函数名的函数声明和函数体组成:
闭包 —— Go的匿名函数是一个闭包。
 
《错误处理》
1. error接口
2. defer—— 统一释放资源,类似于PHP的 __destruct()
3. panic() 和 recover()
 
《面向对象》
1.类型系统:
2.值语义 和 引用语义
(1)要想表达引用,需要使用“指针”:(个人理解,类似于PHP的引用传递: & )
(2)Go语言中四个类型看起来像引用类型的类型:
(3)结构体 (struct)
(4)初始化:
(5)可见性 (类似于PHP的 private/protected/public的意思,但是Go语言中没有这样的关键字)
要是某个符号对其他包可见(可以访问),需要将该符号定义为以大写字母开头。
 
《接口》
在Go语言中,一个类只需要实现了接口要求的所有函数,我们就说这个类实现了该接口。(非侵入式接口)
 
《协程》
goroutine 就是协程,Golang 的一大特色就是从语言层面原生支持协程,在函数或者方法前面加 go关键字就可创建一个协程。
当被调用的函数返回时,这个goroutine也自动结束。
package main
func say(s string) {
for i := 0; i < 5; i++ {
println(s)
}
}
func main() {
go say("Hello")
go say("World")
}
如果运行上面代码,会发现什么结果都没有。
当使用go启动协程之后,这2个函数就被切换到协程里面执行了,但是这时候主线程结束了,这2个协程还没来得及执行就挂了!
聪明的小伙伴会想到,那我主线程先睡眠1s等一等?Yes, 在main代码块最后一行加入:
time.Sleep(time.Second*1) # 表示睡眠1s
你会发现可以打印出5个Hello 和 5个World,多次运行你会发现Hello 和 World 的顺序不是固定的,这进一步说明了一个问题,那就是多个协程是同时执行的。
 
原文地址:https://www.cnblogs.com/rxbook/p/10912704.html