Go Slice进行参数传递如何实现详解

 更新时间:2022年12月12日 10:55:55   作者:捶捶自己  
这篇文章主要为大家介绍了Go Slice进行参数传递如何实现的过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

先了解什么是defer

Go语言中的defer与return执行的先后顺序

Go语言的 defer 语句会将其后面跟随的语句进行延迟处理,在 defer 归属的函数即将返回时,将延迟处理的语句按 defer 的逆序进行执行.也就是说,先被 defer 的语句最后被执行,最后被 defer 的语句,最先被执行。(与栈的先入后出是一个道理,也可以将其理解为入栈和出栈)

举一个简单的例子

func main() {
   a, b := 111, 333
   defer fmt.Println("b= ", b)
   fmt.Println("a= ", a)
}
打印结果:
a=  111
b=  333

可以看到虽然执行语句时b在前,但是输出结果为b在最后被输出。

defer 的用法

(简单讲解,细节请自行查阅资料)

一般用来释放资源或者读写操作,当处理业务或逻辑中涉及成对的操作是一件比较烦琐的事情,比如打开和关闭文件、接收请求和回复请求、加锁和解锁等。在这些操作中,最容易忽略的就是在每个函数退出处正确地释放和关闭资源。比如下面一个例子

func main(){
    a := 1
    out := bufio.NewWriter(os.Stdout)
    defer out.Flush()
    fmt.Fprintln(out, a)
}
输出结果:
1

就可以在最后将结果打印到控制台中去,类似的用法如关闭数据库资源等等。如果这个例子太过于简单,那么来看下个例子。

var a bool = true
defer func() {
   fmt.Println("1")
}()
if a == true {
   fmt.Println("2")
   return
}
defer func() {
   fmt.Println("3")
}()
输出结果:
2
1

我们会发现defer语句也是需要被执行的,如果在defer函数执行之前就执行return。defer后的语句就不会再被执行了。但是如果是在return之前defer已经执行,则defer中的语句将会在return执行之前先一步进行执行.

那么defer 和 return有什么联系?

defer 是延迟执行语句,return是返回语句,那么肯定出现谁先谁后的问题。下面看一个经典的例子吧

func increaseA() int {
	var i int
	defer func() {
		i++
	}()
	return i
}
func increaseB() (r int) {
	defer func() {
		r++
	}()
	return r
}
func main() {
	fmt.Println(increaseA())
	fmt.Println(increaseB())
}
输出结果为:
0
1

肯定有人觉得有疑惑,为什么A函数没有输出,B函数却输出了呢?为什么答案不是1和0呢?

原因:

先说结论:defer 修饰的匿名函数,只能更新具名返回值.那么这会导致什么问题呢?我们来逐步分析这个例子。

  • 在increaseA()函数中有一个声明i,表示i在该函数内已经被生成,是有名称的变量。但该函数返回参数为匿名参数.
  • 在increaseB()函数中没有声明r,是匿名变量。但该函数返回参数为具名参数.
  • func increaseA() int,返回值i=0的时候该值已经被绑定到返回值里了,defer再去改i已经没用了.
  • func increaseB() (r int), 返回值r先把返回变量设为0,defer又把r改为1.这时候还能生效. 因此答案很明显为 1 和 0.

更进一步理解

我们若想要进一步理解也可以去输出汇编语句,然后进行研读,可惜我是个菜鸟读不懂汇编语言!但我们可以从return入手

我们要理解return 返回值的运行机制:

return并非原子操作,分为赋值,和返回值两步操作.实际上return 执行了两步操作,因为返回值没有命名,所以return默认指定了一个返回值(假设为a),首先将i赋值给a,后续的操作因为是针对i进行的,所以不会影响a, 此后因为a不会更新,所以return a不会改变.

var i int  
a := i  
return a

但是如果return的参数a是具名参数,就像上述例子中increaseB()函数一样。a就相当于命名的变量i, 因为所有的操作都是基于命名变量i(a),返回值也是i, 所以每一次defer操作,都会更新返回值i.

省流小结

return会将返回值先保存起来,对于无名返回值来说,保存在一个临时对象中,defer是看不到这个临时对象的;而对于有名返回值来说,就保存在已命名的变量中。

以上就是Go语言defer与return执行的先后顺序详解的详细内容,更多关于Go defer return执行顺序的资料请关注脚本之家其它相关文章!

相关文章

  • Golang分布式应用之Redis示例详解

    Golang分布式应用之Redis示例详解

    这篇文章主要为大家介绍了Golang分布式应用之Redis示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • Golang中的godoc使用简介(推荐)

    Golang中的godoc使用简介(推荐)

    Godoc是go语言的文档化工具,类似于文档化工具godoc,类似于Python的Docstring和Java的Javadoc,这篇文章主要介绍了Golang中的godoc使用简介,需要的朋友可以参考下
    2022-10-10
  • Golang IPv4 字符串与整数互转方式

    Golang IPv4 字符串与整数互转方式

    这篇文章主要介绍了Golang IPv4 字符串与整数互转方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • 如何使用Go检测用户本地是否安装chrome

    如何使用Go检测用户本地是否安装chrome

    这篇文章主要为大家详细介绍了如何使用Go检测用户本地是否安装chrome,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-10-10
  • Golang中实现类似类与继承的方法(示例代码)

    Golang中实现类似类与继承的方法(示例代码)

    这篇文章主要介绍了Golang中实现类似类与继承的方法,Go语言中通过方法接受者的类型来决定方法的归属和继承关系,本文通过示例代码讲解的非常详细,需要的朋友可以参考下
    2024-04-04
  • 解决golang结构体tag编译错误的问题

    解决golang结构体tag编译错误的问题

    这篇文章主要介绍了解决golang结构体tag编译错误的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-05-05
  • golang http请求未释放造成的错误问题

    golang http请求未释放造成的错误问题

    这篇文章主要介绍了golang http请求未释放造成的错误问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • Golang中的panic之避免和处理程序中的异常情况

    Golang中的panic之避免和处理程序中的异常情况

    Golang中的panic是一种异常处理机制,可以在程序出现异常情况时终止程序并打印错误信息。为了避免panic对程序的影响,开发者可以采用一系列技巧,如defer+recover、编写可重入的代码、使用错误返回值等。这些技巧可以帮助开发者优雅地处理程序中的异常情况
    2023-04-04
  • 利用Go语言实现流量回放工具的示例代码

    利用Go语言实现流量回放工具的示例代码

    今天给大家推荐一款使用Go语言编写的流量回放工具 -- goreplay;工作中你一定遇到过需要在服务器上抓包的场景,有了这个工具就可以助你一臂之力,废话不多,我们接下来来看一看这个工具
    2022-09-09
  • GoLang channel关闭状态相关操作详解

    GoLang channel关闭状态相关操作详解

    Channel 和 goroutine 的结合是 Go 并发编程的大杀器。而 Channel 的实际应用也经常让人眼前一亮,通过与 select,cancel,timer 等结合,它能实现各种各样的功能。接下来,我们就要介绍GoLang channel关闭状态相关操作
    2022-10-10

最新评论