Go 语法基础夯实

本文详细介绍了在Linux系统中使用Ubuntu进行Go语言的学习和环境配置,涵盖了Go语言的基础概念如变量、常量、运算符、结构体、数组、切片、条件句、循环、函数、闭包、指针、方法、接口、error处理以及defer语句的使用。同时讨论了依赖管理和常见问题解决方法。
摘要由CSDN通过智能技术生成

一、学习指引

二、Ubuntu系统

操作与使用:https://zhuanlan.zhihu.com/p/672688377

linux常用命令:https://blog.csdn.net/m0_46422300/article/details/104645072

三、环境安装和配置

  • 在linux系统中安装go环境:https://www.bilibili.com/video/BV1gf4y1r79E?p=2&vd_source=7ac1840ef91fce196a35d848a3779e29
  • 在linux系统中安装goland:https://blog.csdn.net/sanqima/article/details/113623671
  • goland常用快捷键:https://zhuanlan.zhihu.com/p/548611534
  • goland上手:https://zhuanlan.zhihu.com/p/120347718 目前在使用go.mod方式下,不需要进行gopath的设置也行
  • goroot&gopath&gomodule参见此文:https://blog.csdn.net/qq_38151401/article/details/105729884

四、Go基础夯实

4.1 go语言结构

  • 环境变量配置:

  • package&module:https://juejin.cn/post/6869570760738865166

4.2 变量和常量

  • 介绍:https://zhuanlan.zhihu.com/p/143087271
  • 注意点:
  • 只允许在函数体内使用语法糖对变量进行声明和赋值
  • 声明了一个局部变量却没有在相同的代码块使用,同样会编译错误
  • 全局变量允许声明但不使用
  • 全局变量的生命周期是程序存活时间
  • 在不发生内存逃逸的情况下,局部变量是函数存活时间

4.3 go语言运算符

  • 介绍:https://segmentfault.com/a/1190000044201272
  • 运算符优先级:

4.4 go语言结构体

  • 介绍:https://blog.csdn.net/m0_37710023/article/details/107657413  https://zhuanlan.zhihu.com/p/654946733

4.5 go语言数组与切片

  • 数组介绍:https://www.runoob.com/go/go-arrays.html
  • 切片介绍:https://zhuanlan.zhihu.com/p/629420925
  • map介绍:https://blog.csdn.net/weixin_43529465/article/details/129036783
  • map底层原理:https://zhuanlan.zhihu.com/p/460958342

4.6 go语言条件句

  • 介绍:https://blog.csdn.net/wohu1104/article/details/99006545
  • if 语句特点:
  • if 后面的条件判断子句不需要用小括号括起来;
  • { 必须放在行尾,和 if 或者 else if 放在一行;
  • if 后面可以带一个简单的初始化语句,并以分号分割,该简单语句声明的变量的作用域是整个 if 语句块,包括后面的 else if else 分支;
  • if 分支语句遇到 return 后直接返回,遇到 break 则跳过 break 下方的 if 语句块;
  • switch语句特点:
  • switch 和 if 语句一样, switch 后面可以带一个可选的简单的初始化语句;
  • switch 后面的表达式也是可选的,如果没有表达式, 则 case 子句是一个布尔表达式,而不是一个值,此时就相当于多重 if else 语句;
  • switch 条件表达式的值不像 C/C++ 语言那样必须限制为整数常量, 表达式不需要为常量,甚至不需要为整数,可以是任意支持相等比较运算的类型变量;
  • switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止;
  • switch 语句执行的过程从上至下,直到找到匹配项,匹配项后面也不需要再加 break ;
  • switch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case,如果我们需要执行后面的 case,可以使用 fallthrough
  • switch 支持 default 语句, 当所有的 case 分支都不符合时, 执行 default 语句, 并且 default 语句可以放到任意位置,并不影响 switch 的判断逻辑;

4.7 go语言循环

  • 介绍:https://blog.csdn.net/weixin_44211968/article/details/121251817

4.8 go语言函数

  • 介绍:https://www.runoob.com/go/go-functions.html
  • 闭包:(匿名函数+捕获的变量)

Go
package main

import "fmt"

func adder() func(int) int {
        sum := 0
        return func(x int) int {
                fmt.Println("
执行前 sum =", sum)
                sum += x
                return sum
        }
}

func main() {
        pos := adder()
        for i := 0; i < 4; i++ {
                fmt.Println("执行后 sum =", pos(1))
        }

以上程序执行过程:

当程序执行main函数时,首先调用adder函数并将返回的闭包函数赋值给pos变量。在adder函数中,定义了一个sum变量,并返回一个闭包函数,闭包函数引用了外部的sum变量。

接着进入for循环,循环4次。每次循环中调用pos(1),传入参数1。闭包函数内部会打印当前sum的值,然后将参数值加到sum上,并返回新的sum值。

下面是程序的运行流程:

  1. i=0 时,执行 pos(1):
  • 输出 "执行前 sum = 0"
  • sum = sum + 1,即 sum = 0 + 1 = 1
  • 输出 "执行后 sum = 1"
  1. i=1 时,执行 pos(1):
  • 输出 "执行前 sum = 1",之前的sum值为1
  • sum = sum + 1,即 sum = 1 + 1 = 2
  • 输出 "执行后 sum = 2"
  1. i=2 时,执行 pos(1):
  • 输出 "执行前 sum = 2",之前的sum值为2
  • sum = sum + 1,即 sum = 2 + 1 = 3
  • 输出 "执行后 sum = 3"
  1. i=3 时,执行 pos(1):
  • 输出 "执行前 sum = 3",之前的sum值为3
  • sum = sum + 1,即 sum = 3 + 1 = 4
  • 输出 "执行后 sum = 4"

通过闭包函数,sum变量得以保留并且可以在每次调用闭包函数时被修改和访问,形成了类似于对象的状态。这种特性使得闭包函数在Go语言中非常灵活和强大。

adder函数在main函数中被调用并返回闭包函数给pos变量时,adder函数的生命周期会至少持续到程序执行完毕。因为返回的闭包函数中引用了adder函数作用域内的sum变量,所以add函数不会在其作用域结束后立即被销毁,而是会保持活跃状态,直至所有引用它的闭包函数被销毁。(在这个例子中,由于闭包函数持续引用着adder函数作用域内的变量,adder函数的生命周期会持续到所有引用它的闭包函数都被销毁为止。)

4.9 go语言指针

  • 介绍:https://zhuanlan.zhihu.com/p/630590733
  • make与new的区别:https://c.biancheng.net/view/5722.html#

4.10 go语言方法

  • 介绍:https://blog.csdn.net/wohu1104/article/details/106202918
  • 方法是面向对象的,函数是面向过程的
  • 接口类型不能作为方法的receiver基类,但是可以作为函数的参数和返回值

4.11 go语言接口

  • 介绍:https://juejin.cn/post/7060471869085843487
  • 一个对象只要全部实现了接口中的方法,那么就实现了这个接口(无论是自定义的还是内置的)。换句话说,接口就是一个需要实现的方法列表。一个对象可以实现多个接口,一个接口也可以被多个对象实现。

4.12 go语言error

  • 介绍:https://cloud.tencent.com/developer/article/2232185

4.13 go语言defer

  • go语言的一个关键字,用在函数或者方法前面,延迟函数的执行:defer func()
  • 延迟函数什么时候被调用:(一定会被执行,无论是否正常退出)
  • 函数return的时候
  • 发生panic的时候
  • 延迟调用的语法规则
  • defer关键字后面表达式必须是函数或者方法调用
  • 延迟内容不能被括号括起来
  • 多个defer同时出现时,按倒序执行,先定义的后执行
  • defer的使用场景
  • 资源释放
  • 配合recover捕获异常
  • defer考点:
  • 代码考察,通过defer修改函数放回值,考察输出。
  • defer与return的关系:https://cloud.tencent.com/developer/article/1453355(非常好,一看就懂)
  • return非原子操作,其执行的过程可分为三步:
  • 设置返回值,对于无名返回值,这个返回值保存在一个临时空间中(该空间不同于函数中为局部变量i开辟大空间),defer时看不到这个临时空间(与局部变量i地址不同),只能看到局部变量的地址,所以defer函数中对i的操作也能正常执行,但是因为不是对返回值空间进行的操作,所以返回值只会为局部变量被定义时取得的那个值(因为设置返回值快于defer,故不是defer函数执行后的i值);而对于有名返回值,就保存在已命名的变量中,故defer能看到这个返回值(同一地址),后续的操作也对这个地址的返回值操作。
  • 执行defer语句
  • 将结果返回

4.14 go异常捕获

  • 介绍:https://www.cnblogs.com/open-yang/p/11256858.html
  • defer嵌套写法的解析:https://juejin.cn/post/7197361396220100663

Go
// 第一种
func main() {
  x := 1
  y := 2
  defer calcTest("AA", x, calcTest("A", x, y))
  x = 10
  defer calcTest("BB", x, calcTest("B", x, y))
  y = 20
}

func calcTest(index string, a, b int) int {
  ret := a + b
  fmt.Println(index, a, b, ret)
  return ret
}
/*
A 1 2 3
B 10 2 12
BB 10 12 22
AA 1 3 4
*/

func main() {
  x := 1
  y := 2
  defer func() {
    calcTest("AA", x, calcTest("A", x, y))
  }()
  x = 10
  defer func() {
    calcTest("BB", x, calcTest("B", x, y))
  }()
  y = 20
}
/*
B 10 20 30
BB 10 30 40
A 10 20 30
AA 10 30 40
*/

defer语句后面,如果未使用嵌套写法,这时函数里的参数值都得为确定值(先确定参数,但推迟整个函数的执行),即不会因为后面的修改而影响;如果使用嵌套写法,由于匿名函数无参数,需进入函数体内后才开始确定calcTest里面的参数,故得到的是xy的最终结果

所以,例子1执行顺序:先执行输出A→B,然后defer逆序执行输出BB→AA例子2执行顺序:直接defer逆序执行,顺序为B→BB→A→AA,每一步带入相应的x y值,即可推导出结果。

第一种是非匿名函数写法

  1. 初始化变量 x 1
  1. 初始化变量 y 2
  1. 执行 defer calcTest("AA", x, calcTest("A", x, y))
  • 这里会先计算 calcTest("A", x, y),即调用 calcTest 函数并传入参数 "A", 1, 2
  • "A 1 2 3" 被打印出来
  • 然后再计算 calcTest("AA", x, 3),即调用 calcTest 函数并传入参数 "AA", 1, 3
  • "AA 1 3 4" 被打印出来
  • 注意:defer 语句中的函数调用会被推迟到当前函数执行结束之前才执行
  1. 将变量 x 更新为 10
  1. 执行 defer calcTest("BB", x, calcTest("B", x, y))
  • 这里会先计算 calcTest("B", x, y),即调用 calcTest 函数并传入参数 "B", 10, 2
  • "B 10 2 12" 被打印出来
  • 然后再计算 calcTest("BB", x, 12),即调用 calcTest 函数并传入参数 "BB", 10, 12
  • "BB 10 12 22" 被打印出来
  1. 将变量 y 更新为 20
  1. 函数执行结束

第二种是匿名函数的写法

由于使用了defer关键字,所以两个匿名函数都会被推迟到函数执行结束之前才执行,由于匿名函数无参数,所以无需提前确定,所以也是到那个时候才开始进入函数体内后才开始确定calcTest的参数。

  • recover和panic可以总结为以下两点:
  • recover只能回复当前函数级或以当前函数为首的调用链中的函数中的panic(),恢复后当前调用recover的函数结束,但是调用此函数的函数继续执行
  • 函数发生了panic之后会一直向上传递,如果直至main函数都没有recover(),程序将终止,如果是碰见了recover(),将被recover捕获
  • recover必须搭配defer来使用,否则panic捕获不到;
  • defer一定要在可能引发panic语句之前定义

4.15 依赖管理

  • 介绍:https://blog.csdn.net/qq_31930499/article/details/101108056
  • 下载失败可看:https://zhuanlan.zhihu.com/p/525542452
  • 21
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值