Golang基础3-函数、nil相关

函数

    • 需要声明原型
    • 支持不定参数 func sum(numbers ...int)int
    • 支持返回多值
    • 支持递归
    • 支持命名返回参数
// 命名返回参数
func add(a, b int) (sum int) {sum = a + breturn // 这里不需要显式地写出返回值,因为已经在函数签名中声明了命名返回参数
}
    • 支持匿名函数、闭包
    • 函数也是一种类型,函数可以赋值给变量(本质函数指针)
    • 一个包中能有名字一样的函数
    • 不支持:重载(==,!=等等均不支持),默认参数

简单demo

package mainimport "fmt"//测试函数
func test(x, y int, s string) (int, string) {n := x + yreturn n, fmt.Sprintf("%s,%d\n", s, n)
}
func main() {a, b := test(1, 2, "你好")// _可以忽略某些值的返回fmt.Println(a)fmt.Println(b)}

回调函数demo

回调函数本质其实就是函数指针作为形参,传递给了函数,增加了代码的灵活度。

package mainimport "fmt"// 回调函数1
func testFunc(fn func() int) int {return fn()
}// 定义函数类型
type FormatFunc func(s string, x, y int) stringfunc format(fn FormatFunc, s string, x, y int) string {return fn(s, x, y)
}func formatHelper(s string, x, y int) string {return fmt.Sprintf(s, x, y)
}func main() {s1 := testFunc(func() int {return 100})fmt.Println(s1) //100//匿名函数,回调进行格式化返回string//s2 := format(func(s string, x, y int) string {//    return fmt.Sprintf(s, x, y)//}, "%d %d", 10, 20)s2 := format(formatHelper, "%d %d", 10, 20)fmt.Println(s2)
}

闭包demo

闭包很简单,可以理解为返回值是一个函数指针,其他的再看就很好理解了。

https://juejin.cn/post/6844903793771937805

package mainimport ("fmt"
)//返回函数指针 func()int
func a() func() int {i := 0b := func() int {i++fmt.Println(i)return i}return b
}func main() {//a执行完返回func() int 的这个函数指针,其中赋值给c,//那么这里面保存有这个b匿名函数的所有信息,实现了自增,可以不用定义全局变量c := a()c()c()c()//因为这个是函数指针a() //不会输出i
}

递归demo

package mainimport "fmt"// 递归1,求阶乘
func Factorial(n int) int {if n <= 1 {return 1}return n * Factorial(n-1)
}// 递归2,斐波那契数列
func Fibonaci(n int) int {if n == 0 {return 0}if n == 1 {return 1}return Fibonaci(n-1) + Fibonaci(n-2)
}
func main() {fmt.Println("5!=", Factorial(5))fmt.Println("前10项斐波那契数列:")for i := 0; i < 10; i++ {fmt.Printf("%d\t", Fibonaci(i))}
}

异常处理demo

参考文档:异常处理 · Go语言中文文档

使用panic抛出错误,defer捕获错误,一般panic中抛出异常,defer中捕获异常,之后正常处理。

panic:

内置函数,panic后的代码不执行, interface{},直到goroutine整个退出并报告错误,

recover:

1.利用recover处理panic指令,defer 必须放在 panic 之前定义,另外 recover 只有在 defer 调用的函数中才有效。否则当panic时,recover无法捕获到panic,无法防止panic扩散。

2.recover 处理异常后,逻辑并不会恢复到 panic 那个点去,函数跑到 defer 之后的那个点。

3.多个 defer 会形成 defer 栈,后定义的 defer 语句会被最先调用。

painc处理demo

painc会导致程序直接退出,平时开发中尽量不随便使用。

一般场景:我的服务想要启动,必须依赖某些服务、日志、mysql能联通,配置文件没问题,那么才能启动的时候,直接使用panic

一旦服务启动,这时你的某行代码不小心触发panic,那么这就是重大事故(比如别人请求,你直接挂了)

但是架不住有些地方被动触发panic,这时就引入了recover来捕获panic

package mainimport "fmt"// painc部分后面代码不执行
func test() {defer func() {if err := recover(); err != nil {println("recover panic:", err.(string))}}()panic("panic错误测试!")//panic后的代码不执行//fmt.Println("panic后代码")
}func main() {test()fmt.Println("main")
}

error处理 demo
package mainimport ("errors""fmt"
)func A() (int, error) {return 2, errors.New("this is an error")}func main() {if _, err := A(); err != nil {fmt.Println(err)}
}

recover捕获panic的demo

recover需要延迟调用,也就是必须在defer的函数内部,否则返回nil

package mainimport "fmt"func except() {fmt.Println("except延迟函数调用!")fmt.Println("except延迟函数recover:", recover())
}func recoveryDemo() {//等效于下面的匿名延迟函数defer except()//延迟调用,recover在函数内部defer func() {if err := recover(); err != nil {fmt.Println("有效", err.(string))}}()//defer recover()              //无效,不是延迟调用,nildefer fmt.Println(recover()) //无效,空defer func() {func() {fmt.Println("defer inner")fmt.Println("defer inner", recover()) //无效}()}()panic("panic错误测试!")//不会执行fmt.Println("End of test!")
}func main() {recoveryDemo()fmt.Println("main")
}

总结:需要recover捕获panic时defer延迟函数进行接受,并且第一个有效的recover只能捕获最后一个painc(如果多个panic),之后有效的recover也返回nil。

defer的使用

defer延迟调用,一般释放资源和连接、关闭文件、释放锁等等。类似于java的finally和c++中析构函数,不过defer一般跟在函数或方法中。

参考博客:【Golang】Go语言defer用法大总结(含return返回机制)_golang defer return-CSDN博客

多个defer满足后进先出

defer跟无参、有参函数、方法
package mainimport "fmt"
//无返回值
func test(a int) {defer fmt.Println("defer1 = ", a)//方法defer func(v int) {fmt.Println("defer2 = ", v)}(a)//有参函数defer func() {fmt.Println("defer3 = ", a)}()//无参函数a += 100
}func main() {test(0)
}

defer满足后进先出,其次,有参情况下a会先传递进入,最后等a+=100之后执行完了再输出。

可读取函数返回值(return返回机制)

先return结构写入返回值,后defer收尾,最后携带返回值退出.

无名返回值,有名返回值的区别,见下面demo

无名有名返回值defer的demo

函数返回值可以无名、有名,这个是方便理解的不全代码,有名res的话本质局部变量,因此defer后会可能会影响res的返回值。而int这个返回值就直接定了。这个很容易引起bug,因此看下面例子:

package mainimport "fmt"// 无名返回值
func UnNamed(n int) int {n += 100defer func() {n += 100fmt.Println("UnNamed defer1", n)}()return n
}// 有名返回值
func Named(n int) (res int) {res = n + 100defer func() {res += 100fmt.Println("UnNamed defer1", res)}()// 返回res局部变量,因此受defer中的res的逻辑影响return res
}func main() {n := 0fmt.Println("main UnNamed return:", UnNamed(n))fmt.Println("main Named return:", Named(n))
}

对于第一无名返回值,先执行return保存返回值100,之后defer输出200,最后返回到main函数为100.

第二有名返回值,先执行return知道返回的是res(此时100),之后defer修改输出res200,最终返回到main为200.

同理可以更复杂,defer可以传入形参的无名有名函数,可以进行分析。

package mainimport "fmt"// 无名返回值
func UnNamed(n int) int {n += 100defer func(n int) { //传入100,输出110n += 10fmt.Println("UnNamed defer2", n)}(n)defer func() { //200n += 100fmt.Println("UnNamed defer1", n)}()return n //100
}// 有名返回值
func Named(n int) (res int) {res = n + 100 //100defer func(res int) { //传入100并且注意是值拷贝,并且入栈,110res += 10fmt.Println("UnNamed defer2", res)}(res)defer func() { //入栈res += 100fmt.Println("UnNamed defer1", res)}()return res //100->200
}func main() {n := 0fmt.Println("main UnNamed return:", UnNamed(n)) //100fmt.Println()fmt.Println("main Named return:", Named(n)) //200
}

因此传入指针等等,defer函数,有无名返回值均会影响main函数中接收到的最终return的值,请注意。

    • 调用os.Exit时defer不会被执行defer
    • 与panic进行配合处理异常

nil相关

nil代表某些数据类型的零值

不同类型0值

bool false

number 0

string ""

slice、map、channel、pointer、interface{} nil

如果是结构体,那么它的零值是,内部所有属性的零值的集合

nil 和empty的区别

这里分析了slice、map中的nil和empty的区别。

package mainimport "fmt"type Student struct {name stringage  int
}func main() {// nil slice,其实可以创建,append对nil slice进行了处理,但是map就不行var s1 []Student//s1 = append(s1, Student{"Bob", 19})fmt.Println(s1)if s1 == nil {fmt.Println("s1==nil")}// 不是nil slice,其实本质上是创建了,内部ptr指向一个空间为0的数组var s2 = make([]Student, 0)if s2 == nil {fmt.Println("s2==nil")}// nil mapvar m1 map[int]Studentif m1 == nil {fmt.Println("m1==nil")}//可以查询,但是无法添加键值对,panic(assignment to entry in nil map)//m1[1] = Student{"hhh", 123}//if val, ok := m1[1]; ok {//    fmt.Println("ok", val)//} else {//    fmt.Println("not ok")//}fmt.Println(m1)//不是nil map,已经初始化了,0个空间的mapvar m2 = make(map[int]Student, 0)//可以查询,插入数据了m2[1] = Student{"hhh", 123}if val, ok := m2[1]; ok {fmt.Println("ok", val)} else {fmt.Println("not ok")}fmt.Println(m2)}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2980706.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【刷题】前缀和入门

送给大家一句话&#xff1a; 既然已经做出了选择&#xff0c;最好还是先假定自己是对的。焦虑未来和后悔过去&#xff0c;只经历一个就够了。 – 张寒寺 《不正常人类症候群》 ☆ミヾ(∇≦((ヾ(≧∇≦)〃))≧∇)ノ彡☆ ☆ミヾ(∇≦((ヾ(≧∇≦)〃))≧∇)ノ彡☆ ☆ミヾ(∇≦((ヾ…

信息系统项目管理师0064:软件实现(5信息系统工程—5.1软件工程—5.1.4软件实现)

点击查看专栏目录 文章目录 5.1.4软件实现1.软件配置管理2.软件编码3.软件测试记忆要点总结5.1.4软件实现 1.软件配置管理 软件配置管理通过标识产品的组成元素、管理和控制变更、验证、记录和报告配置信息,来控制产品的演进和完整性。软件配置管理与软件质量保证活动密切相关…

关于Domain的查询命令

dig: 用来执行DNS查询&#xff0c;可以获取指定域名的所有类型的DNS记录。对网络管理员和开发人员尤其有用。 host: 一个简化版的DNS查询工具&#xff0c;适合快速查询域名的IP地址或某种类型的DNS记录。 nslookup: 另一个DNS查询工具&#xff0c;既支持交互模式也支持命令行模…

简单谈谈URL过滤在网络安全中的作用

用户花在网络上的时间越来越多&#xff0c;浏览他们最喜欢的网站&#xff0c;点击电子邮件链接&#xff0c;或利用各种基于网络的 SaaS 应用程序供个人和企业使用。虽然这种不受约束的网络活动对提高企业生产力非常有用&#xff0c;但也会使组织面临一系列安全和业务风险&#…

线性代数 --- 矩阵的对角化以及矩阵的n次幂

矩阵的对角化以及矩阵的n次幂 &#xff08;特征向量与特征值的应用&#xff09; 前言&#xff1a; 在上一篇文章中&#xff0c;我记录了学习矩阵的特征向量和特征值的学习笔记&#xff0c;所关注的是那些矩阵A作用于向量x后&#xff0c;方向不发生改变的x(仅有尺度的缩放)。线…

面试ssss

响应式布局 响应式布局是一种设计和开发网页的方法&#xff0c;使网页能够适应不同的设备和屏幕尺寸&#xff0c;提供更好的用户体验。它通过使用媒体查询&#xff08;Media Queries&#xff09;和弹性布局&#xff08;Flexbox&#xff09;等技术&#xff0c;根据设备的特性和…

SSH Key生成

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

代码随想录算法训练营DAY32|C++贪心算法Part.2|122.买卖股票的最佳时机II、55.跳跃游戏、45.跳跃游戏II

文章目录 122.买卖股票的最佳时机II思路CPP代码 55.跳跃游戏思路CPP代码 45.跳跃游戏II思路方法一代码改善 CPP代码 122.买卖股票的最佳时机II 力扣题目链接 文章讲解&#xff1a;122.买卖股票的最佳时机II 视频讲解&#xff1a; 状态&#xff1a;本题可以用动态规划&#xff0…

构建NodeJS库--前端项目的打包发布

1. 前言 学习如何打包发布前端项目&#xff0c;需要学习以下相关知识&#xff1a; package.json 如何初始化配置&#xff0c;以及学习npm配置项&#xff1b; 模块类型type配置&#xff0c; 这是nodejs的package.json的配置main 入口文件的配置 webpack 是一个用于现代 JavaSc…

Linux加强篇-存储结构与管理硬盘(一)

目录 ⛳️推荐 从“/”开始 物理设备命名规则 文件系统与数据资料 ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站 从“/”开始 Linux系统中一切都是文件&#xff0c;都是从“…

深度解析:云计算的三宝——IaaS、PaaS和SaaS

4月22日&#xff0c;腾讯宣布旗下协作SaaS产品全面接入腾讯混元大模型&#xff0c;除去企业微信、腾讯会议、腾讯文档等“一门三杰”产品&#xff0c;腾讯乐享、腾讯电子签、腾讯问卷、腾讯云AI代码助手等协作SaaS产品也都已实现智能化升级。大模型应用落地再加速。 那么什么是…

HarmonyOS开发案例:【相机开发】

基本概念 相机是OpenHarmony多媒体进程提供的服务之一&#xff0c;提供了相机的录像、预览、拍照功能&#xff0c;支持多用户并发取流。 在进行应用的开发前&#xff0c;开发者应了解以下基本概念&#xff1a; 视频帧 视频流指的是将一系列图片数据按照固定时间间隔排列形成的…

牛客社区所有的表和SQL语句

文章目录 1 帖子表 discuss_post1.1 字段描述1.2 相关功能描述1.2.1 分页查询帖子1.2.2 查询帖子总数量1.2.3 插入一条帖子记录1.2.4 根据帖子ID查询某条帖子1.2.5 更新帖子评论数量1.2.6 更新帖子类型1.2.6 更新帖子状态1.2.7 更新帖子分数 2 用户表 user2.1 字段描述2.2 相关…

【七】jmeter5.5+influxdb2.0+prometheus+grafana

参考文章&#xff1a;https://blog.csdn.net/wenxingchen/article/details/126892890 https://blog.csdn.net/Zuo19960127/article/details/119726652 https://blog.csdn.net/shnu_cdk/article/details/132182858 promethus参考 由于自己下载的是infuldb2.0&#xff0c;所以按照…

云Docker部署Guacamole经frp中转远程连接Windows

安装frps sudo nohup ./frps -c frps.ini >/dev/null 2>&1 & frps.ini [common] bind_port 7000# Virtual host configuration vhost_http_port 80 vhost_https_port 443# Dashboard configuration dashboard_addr 0.0.0.0 dashboard_port 7500 dashboar…

自然语言处理 (NLP) 的技术演变史

一、简述 本文的目标是了解自然语言处理 (NLP) 的历史&#xff0c;包括 Transformer 体系结构如何彻底改变该领域并帮助我们创建大型语言模型 (LLM)。 基础模型&#xff08;如 GPT-4&#xff09;是最先进的自然语言处理模型&#xff0c;旨在理解、生成人类语言并与之交互。 要理…

FebHost:科技企业如何规划并注册.AI域名?

为确保企业使用.AI域名的方式准确反映其对人工智能技术的关注&#xff0c;企业应考虑以下步骤&#xff1a; 了解法律和合规要求&#xff1a; 第一步是了解与 .AI 域名相关的独特法律和合规要求。由于.AI域名源于安圭拉&#xff0c;企业必须遵守安圭拉的限制和法律规定。这包括…

(Oracle)SQL优化案例:组合索引优化

项目场景 项目上的ETL模型里有如下SQL语句。执行速度非常慢&#xff0c;每次只查询200条数据&#xff0c;但却需要20多秒的时间。再加上该SQL查询出的数据同步频率很高&#xff0c;这个速度是完全不能忍受的。 因为项目隐私&#xff0c;所以对表及字段做了改写。 SELECT ID…

服务器(AIX、Linux、UNIX)性能监视器工具【nmon】使用介绍

目录 ■nmon简介 1.安装 2.使用简介 3.使用&#xff08;具体使用的例子【CPU】【内存】&#xff09; 4.采集数据 5.查看log&#xff08;根据结果&#xff0c;生成报表&#xff09; 6.分析结果 ■nmon简介 nmon&#xff08;"Nigels performance Monitor"&…

Laravel 6 - 第十一章 中间件

​ 文章目录 Laravel 6 - 第一章 简介 Laravel 6 - 第二章 项目搭建 Laravel 6 - 第三章 文件夹结构 Laravel 6 - 第四章 生命周期 Laravel 6 - 第五章 控制反转和依赖注入 Laravel 6 - 第六章 服务容器 Laravel 6 - 第七章 服务提供者 Laravel 6 - 第八章 门面 Laravel 6 - …