*接:最全&最简洁的Go语言入门整理资料 (1)
https://blog.csdn.net/qq_42346574/article/details/109232274
三. Go语言基础
2. 流程控制
//if else(分支结构): 主要是括号的位置及省略的表达式的括号;
if 表达式1 {
分支1
} else if 表达式2 {
分支2
} else{
分支3
}
注意:if匹配的左括号必须与if 表达式在同一行,else也必须和上一个if语句的右括号在同一行 且 与else匹配的括号也要在同一行。
//for (循环结构):
//情况一:
func forDemo() {
for i := 0; i < 10; i++ {
fmt.Println(i)
}
}
//情况二:
func forDemo2() {
i := 0
for ; i < 10; i++ {
fmt.Println(i)
}
}
//情况三:(初始语句和结束语句都可以省略,类似于while)
func forDemo3() {
i := 0
for i < 10 {
fmt.Println(i)
i++
}
}
//无限循环:
for {
循环体语句
}
//在Go中没有其它语言中例如while这类的循环关键词,通常是使用for来代替。
for range(键值循环):
针对不同类型数据返回值不同:
- 数组、切片、字符串返回索引和值。
- map返回键和值。
- 通道(channel)只返回通道内的值。
//switch语句:
switch case:
例如: switch A:=3; A {
case 1:
语句
fallthrough /*fallthrough 语法可以执行满足条件的case的下一个case,即case2的语句。通常是用来简化判断语句 */
case 2:
default:
}
//总的来说这个用法与其他语言比较类似。
goto(跳转到指定标签)
比如:条件判断满足的时候
goto breaktag
breaktag:
fmt.Println("结束for循环") //这样子可以快速跳出多层循环
//这样可以快速跳出循环,在多层循环中可以减少条件判断语句,快速跳出循环。
break 和 continue的用法与C语言一样。
3. 数组、切片、map数据类型
- 数组相关知识:
//数组array:
// 定义一个长度为3元素类型为int的数组a --> var a [3]int
初始化方法:
方法1:
var a [3]int //自动初始化为int类型的0值
var numArray = [3]int{1, 2}
var cityArray = [3]string{"北京", "上海", "深圳"}
方法2:
var numArray = [...]int{1, 2}
var cityArray = [...]string{"北京", "上海", "深圳"}
方法3:
a := [...]int{1: 1, 3: 5} //1:1表示索引从0到1,第二位是1,3:5是第四位是5。
数组遍历:
for i := 0; i<len(a); i++ {
}//或者
for index, value := range a {
}
Go语言是支持多维数组的,用法都比较类似。注意多维数组只有第一层可以使用...来让编译器推导数组长度。
- 切片的相关知识:
//切片slice:
切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。
定义:var name []T
-->在go语言中nil是一个经常使用的,重要的预先定义好的标识符。它是许多中类型的零值表示。
可以使用make()函数构造切片:make([]T, size, cap) //T元素类型、size切片元素数量、cap切片的容量
a := make([]int, 2, 10)
判断切片是否为空:
请始终使用len(s) == 0来判断,而不应该使用s == nil来判断。
-
切片的复制拷贝:
func main() { s1 := make([]int, 3) //[0 0 0] s2 := s1 //将s1直接赋值给s2,s1和s2共用一个底层数组 s2[0] = 100 fmt.Println(s1) //[100 0 0] fmt.Println(s2) //[100 0 0] }
-
切片的遍历与数组一致,有索引遍历和for range遍历;
-
append( )方法为切片添加元素:
var s []int //不用进行初始化,可以直接使用append()函数。 s = append(s, 1) // [1] s = append(s, 2, 3, 4) // [1 2 3 4] s2 := []int{5, 6, 7} s = append(s, s2...) // [1 2 3 4 5 6 7] 往s中添加另外一个切片的元素后边要加上...(三个点)
-
切片类型是引用类型,所以在 b := a直接赋值的时候,指向的是同一块内存地址。
使用copy函数复制切片:
copy(destSlice, srcSlice []T)
例如:a := [ ]int {1, 3, 5, 7, 9}
c := make([ ]int, 5, 5)
copy(c, a)//这不是同一块内存空间,所以修改的时候是会有区别的。 -
从切片中删除元素:
Go语言中并没有删除切片元素的专用方法,我们可以使用切片本身的特性来删除元素。比如直接:a = append(a[ :2 ], a[ 3: ]…)这样就把第三个值删除了。
- map数据相关知识:
map数据类型:
1.map定义为map[KeyType] ValueType
2.也可以使用make()来分配内存,语法为
make(map[KeyType]ValueType, [cap])
3.判断某个键是否存在?
scoremap := make(map[string]int)
scoremap[“Hao”] = 100
socremap[“Leo”] = 60
v, ok := scoremap[“Hao”]
if ok {
fmt.Println(v)
} else {
fmt.Println(“查无此人!”)
}
4.map遍历:
for k, v := range map {
fmt.Println(k, v)
}//只想遍历key的时候
for k := range map {
fmt.Println(k)
}
注意: 遍历map时的元素顺序与添加键值对的顺序无关。
5.map中删除键值对
delete(map, key) 例如 delete(scoremap, “张三”)
6.按照指定的顺序遍历map
申请切片空间–>将map中的key值存到切片空间中–>对该切片进行排序–>最后按照排序后的key遍历map
7.切片类型map
slicemap := make(map[string][ ]string, 3)
key := “中国”
k, ok := slicemap[key]
if !ok {
value = make([]string, 0, 2)
}
value = append(value, “BJ”, “SH”)
slicemap[key] = value
4. 函数
函数定义:
func 函数名(参数)(返回值){
函数体
}
参数:
1.类型简写成 (x,y int)
2.可变参数:(x... int) //x是一个切片类型 可变参数是通过切片来实现的。
返回值:
3.多返回值用()包裹起来,(int, int) 需要返回return sum, sub
或者是直接在函数定义的时候直接给返回值命名,(sum, sub int) 则返回的时候直接return
再或者返回的东西是空的切片之类的,则可以用nil来代替;
变量的作用域:
4.全局变量:定义在函数外 var n int = 100
5.局部变量:函数内定义的无法在函数外使用,如果局部变量和全局变量重名时,优先访问局部变量。
函数类型与变量:
type可以来定义一个函数类型,calculation类型就是一种函数类型,这种函数接收两个int参数并且返回一个int类型的返回值。
比如:func add(x, y int) int {
return x + y
}
var c caculation
c = add //然后c就可以跟add一样调用 c(2, 4)
高阶函数:分为函数作为参数和函数作为返回值两部分。
1.作为参数如下:
func add (x, y int) int{
return x + y
}
func sub (x, y int) int{
return x - y
}
func calcu(x, y int, op func (int, int) int) int {
return op(x, y)
}
func main() {
ret2 := calcu(10, 20, add)
fmt.Println(ret2) //30
}
2.作为返回值:
func do(s string) (func(int, int) int, error) {
switch s {
case "+":
return add, nil
case "-":
return sub, nil
default:
err := errors.New("无法识别的操作符")
return nil, err
}
}
匿名函数和闭包:
1.匿名函数:
是没有函数名的函数,函数作为返回值因此在函数内部就不能像之前那样定义函数了。由于没有函数名所以它不能像普通函数那样调用,所以匿名函数需要保存到某个变量或作为立即执行数;
// 将匿名函数保存到变量
add := func(x, y int) {
fmt.Println(x + y)
}
add(10, 20) // 通过变量调用匿名函数
//自执行函数:匿名函数定义完加()直接执行
func(x, y int) {
fmt.Println(x + y)
}(10, 20)
匿名函数多用于实现回调函数和闭包。
2.闭包:
闭包指的是一个<函数> + <引用环境>组合而成的实体。
func add(x int) func(int) int {
return func (y int) int {
x += y
return x
}
}
func mian() {
var f = add(10) //在f的生命周期中变量x一直有效此时的f就是一个闭包
fmt.Println(f(10)) //20
fmt.Println(f(20)) //40
var f1 = add(20)
fmt.Println(f1(20))//40
}
两个函数的情况:
func calcu(base int) (func(int) int, func(int) int) {
add := func(i int) int {
base += i
return base
}
sub := func(i int) int {
base -= i
return base
}
return add, sub
}
func main() {
f1, f2 := calcu(10)
fmt.Println(f1(1), f2(2))//11, 9
fmt.Println(f1(3), f2(4))//12, 8
}
defer语句:
defer语句是会将后边跟随的语句进行延迟处理,在defer归属的函数即将返回执行的时候,则将延迟的所有语句按照defer定义的逆序进行执行。
defer经典案例:这个搞懂稍微比较复杂,需要自行去查阅相关的资料,我目前也没弄得十分明白/(ㄒoㄒ)/~~
func f1() int {
x := 5
defer func() {
x++
}()
return x
}
func f2() (x int) {
defer func() {
x++
}()
return 5
}
func f3() (y int) {
x := 5
defer func() {
x++
}()
return x
}
func f4() (x int) {
defer func(x int) {
x++
}(x)
return 5
}
func main() {
fmt.Println(f1()) //5
fmt.Println(f2()) //6
fmt.Println(f3()) //5
fmt.Println(f4()) //5
}
内置函数:
close 主要用来关闭channel
len 用来求长度,比如string、array、slice、map、channel
new 用来分配内存,主要用来分配值类型,比如int、struct。返回的是指针
make 用来分配内存,主要用来分配引用类型,比如chan、map、slice
append 用来追加元素到数组、slice中
panic和recover 用来做错误处理
panic/recover函数:
Go语言中目前(Go1.12)是没有异常机制,但是使用panic/recover模式来处理错误。
panic可以在任何地方引发,但recover只有在defer调用的函数中有效。见下边的例子:
func funcB() {
defer func() {
err := recover()
//如果程序出出现了panic错误,可以通过recover恢复过来
if err != nil {
fmt.Println("recover in B")
}
}()
panic("panic in B")
}
注:1.recover()必须搭配defer使用。
2.defer一定要在可能引发panic的语句之前定义。
之后我将会继续更新Go语言中的指针、结构体之类知识,开始面向对象的思想啦!还有有关Go语言中的包、接口、反射,以及它最重要的特性:并发概念等的学习笔记。欢迎大家继续关注!谢谢。