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://www.mzph.cn/news/827937.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

面试十七、list和deque

一、 Deque Deque容器是连续的空间&#xff0c;至少逻辑上看来如此&#xff0c;连续现行空间总是令我们联想到array和vector,array无法成长&#xff0c;vector虽可成长&#xff0c;却只能向尾端成长&#xff0c;而且其成长其实是一个假象&#xff0c;事实上(1) 申请更大空间 (…

快速理解Laravel容器(IOC、DI、Provider、Contract)

源码理解思维的提升 分享一些个人见解。 Laravel里面的某些概念&#xff0c;就像魔术一样&#xff0c;看起来很厉害&#xff0c;当知道魔术怎么变的&#xff0c;就会认为也不过如此。所以不必感觉Laravel里有些概念难以理解。 应当抛除被框架约束思维的枷锁&#xff0c;用PHP…

vuetify3.0+tailwindcss+vite最新框架

1、根据vuetify官网下载项目 安装vuetify项目 2、根据tailwindcss官网添加依赖 添加tailwindcss依赖 3、 配置main.ts // main.ts import "./style.css"4、使用 <template><h1 class"text-3xl font-bold underline">Hello world!</…

解密 Grupo MasMovil 使用 ClickHouse 监控无线网络

本文字数&#xff1a;4151&#xff1b;估计阅读时间&#xff1a;11 分钟 作者&#xff1a;Rodrigo Aguirregabiria Herrero, Grupo MasMovil 审校&#xff1a;庄晓东&#xff08;魏庄&#xff09; 本文在公众号【ClickHouseInc】首发 我们很高兴与大家分享来自西班牙最大的电信…

数据类型总结

1 引言 在计算机的世界里&#xff0c;数据类型是被人类定义出来的&#xff0c;方便人去更好地理解、辨别数据。计算机只能识别二进制数&#xff0c;不可能要求写代码时&#xff0c;只是输入一些0/1的东西。通过定义数据类型&#xff0c;可以让人和计算机更好地“沟通”&#x…

如何评价微软发布的Phi-3,手机都可以运行的小模型

前几天才刚刚发布了Llama 3&#xff0c;今天微软就出手了&#xff0c;发布了小而精的phi-3 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 刚刚发布的Phi-3系列小模型技术报告&#xff0c;引起AI圈热议。 添加图片注释&#xff0c;不超过 140 字&#x…

光接入网络的超宽带半导体光放大器

添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 新颖的双有源层结构获得宽增益光谱&#xff0c;应用于多波单纤双向光放大 ----翻译Xiao Sun等人2016年撰写的文章&#xff0c;文中给出了宽光谱SOA的一种新颖的结构设计方法和仿真结果&#xff0c;但并未给…

蓝海彤翔作为协办单位参加2024陵水全球招商大会

4月16日&#xff0c;2024 陵水全球招商大会在海口第四届中国国际海南消费品博览会期间举办。蓝海彤翔作为本次大会的协办单位&#xff0c;将海南蓝陵数字科技有限公司与海南陵水国际数字内容产业平台落户陵水&#xff0c;标志着蓝海彤翔在数字内容产业领域迈出了坚实的一步&…

上位机图像处理和嵌入式模块部署(树莓派4b与视觉slam十四讲)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 实际使用中&#xff0c;树莓派4b是非常好的一个基础平台。本身板子价格也不是很贵&#xff0c;建议大家多多使用。之前关于vslam&#xff0c;也就是…

【黑马点评Redis——003优惠券秒杀4——消息队列Stream】

1. 目前还存在的问题 设置的阻塞队列可能会超出最大长度系统重启会导致阻塞队列中的信息消失&#xff0c;可能会出现问题 2. 消息队列 消息队列 (Message Queue)。 字面意思就是存放消息的队列。最简单的消息队列模型包括3个角色消息队列:存储和管理消息&#xff0c;也被称为…

甲醛传感器ETO-A1在建筑装修过程中甲醛监测的重要作用

随着建筑装修行业的快速发展&#xff0c;甲醛污染问题逐渐受到人们的关注。甲醛是一种常见的室内空气污染物&#xff0c;主要来源于建筑装修过程中使用的各种材料。为了保障人们的健康和安全&#xff0c;甲醛传感器在装修过程中的监测作用显得尤为重要。英国Alphasense公司推出…

矽塔SA6288Q栅极驱动器,可替代峰绍FD6288Q

SA6288 是一款集成了三个独立半桥栅极驱动器&#xff0c;特别适合于三相电机应用中高速功率MOSFET 和 IGBT 的栅极驱动。可在高达250V 电压下工作。 SA6288内置 VCC 和 VBS 欠压&#xff08; UVLO &#xff09;保护功能&#xff0c;防止功率管在过低的电压下工作&#xff0c;…

记一次 Java 应用内存泄漏的定位过程

问题现象 最近&#xff0c;笔者负责测试的某个算法模块机器出现大量报警&#xff0c;报警表现为机器CPU持续高占用。该算法模块是一个优化算法&#xff0c;本身就是CPU密集型应用&#xff0c;一开始怀疑可能是算法在正常运算&#xff0c;但很快这种猜测就被推翻&#xff1a;同…

springboot基于点餐码 二维码在线点餐系统vue.js+java

Maven: 项目管理和构建自动化工具&#xff0c;用于java项目。 java: 广泛使用的编程语言&#xff0c;适用于构建跨平台应用。 Springmvc:从而在使用Spring进行WEB开发时&#xff0c;可以选择使用Spring的Spring MVC框架。 MyBatis: java持久层框架&#xff0c;支持定制化SQL、存…

第68天:APP攻防-XposedFridaHook证书校验反代理代理转发

目录 思维导图 案例一&#xff1a;某牛防抓包-xposed&frida&r0capture 如何检测是否启动了反代理 xp框架 方案二&#xff1a;某社交防抓包-Proxifier&frida&r0capture 思维导图 案例一&#xff1a;某牛防抓包-xposed&frida&r0capture 这里某牛软…

Python | Leetcode Python题解之第46题全排列

题目&#xff1a; 题解&#xff1a; class Solution:def permute(self, nums):""":type nums: List[int]:rtype: List[List[int]]"""def backtrack(first 0):# 所有数都填完了if first n: res.append(nums[:])for i in range(first, n):# 动…

WebSocket的原理、作用、API、常见注解和生命周期的简单介绍,附带SpringBoot示例

文章目录 原理作用客户端 API服务端 API生命周期常见注解SpringBoot示例 WebSocket是一种 通信协议 &#xff0c;它在 客户端和服务器之间建立了一个双向通信的网络连接 。WebSocket是一种基于TCP连接上进行 全双工通信 的 协议 。 WebSocket允许客户端和服务器在 单个TCP连接上…

基于FPGA轻松玩转AI

启动人工智能应用从来没有像现在这样容易&#xff01;受益于像Xilinx Zynq UltraScale MPSoC 这样的FPGA&#xff0c;AI现在也可以离线使用或在边缘部署、使用.可用于开发和部署用于实时推理的机器学习应用&#xff0c;因此将AI集成到应用中变得轻而易举。图像检测或分类、模式…

Python写个二维码

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、进入官网下载二、下载一下三.输入代码 前言 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、进入官网下载 官网 pip insta…

vue3推荐算法

Vue 3 推荐算法主要指的是在 Vue 3 框架中实现的或者适用于 Vue 3 的算法库或组件库。Vue 3 由于其优秀的设计和性能&#xff0c;被广泛应用于构建各种类型的应用程序&#xff0c;包括需要复杂算法支持的项目。以下是一些在 Vue 3 中可能会用到的推荐算法资源&#xff1a; Vue-…