网络编程
位置:首页>> 网络编程>> Go语言>> Go Slice进行参数传递如何实现详解

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

作者:捶捶自己  发布时间:2024-02-16 13:07:46 

标签: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是看不到这个临时对象的;而对于有名返回值来说,就保存在已命名的变量中。

来源:https://juejin.cn/post/7169591046223953950

0
投稿

猜你喜欢

  • 本文实例讲述了PHP连接MySQL数据库的三种方式。分享给大家供大家参考,具体如下:PHP与MySQL的连接有三种API接口,分别是:PHP
  • 摘要:不同方法读取excel中的多个不同sheet表格性能比较# 方法1def read_excel(path):  df=pd.
  • 前言哈喽铁汁们~新年到了,很多小伙伴都会买上一本日历。现在各种主题各种式样的日历有很多,不过你有没有想过自己定制一套专属的个性化电子日历呢?
  • 作为一个新世纪有思想有文化有道德时刻准备着的 * 丝男青年,在现在这样一个社会中,心疼我大慢播抵制大百度的前提下,没事儿上上网逛逛YY看看斗鱼翻
  • 一个ASP文件通常包含HTML标签,有时和一个HTML文件非常类似。然而,ASP文件(除了包含HTML标签外),还可以包括服务器的脚本程序,
  • 严正声明:本文仅限于技术讨论,严禁用于其他用途。基础知识socket通信模块:针对TCP/IP协议簇进行的程序封装,在Windows/Lin
  • 实现神经网络的权重和偏置更新,很重要的一部就是使用BackPropagation(反向传播)算法。具体来说,反向传播算法就是用误差的反向传播
  • 1 数据导出 python manage.py dumpdata不指定 appname 时默认为导出所有的apppython manage.
  • 本文实例为大家分享了python绘制柱形图的具体代码,供大家参考,具体内容如下#柱形图import pandasimport numpyim
  • 如何让你的CSS代码更具有组织性和易维护性,为什么你的样式表总是臃肿和混乱的?有些时候是源于一开始书写时的混乱和草率,有时候也是因为后期的维
  • imadjustimadjust是一个计算机函数,该函数用于调节灰度图像的亮度或彩色图像的颜色矩阵。在matlab的命令窗口中键入: doc
  • 一、随机数种子为什么要提出随机数种子呢?咱们前面提到过了,随机数均是模拟出来的, 想要模拟的比较真实,就需要变换种子函数内的数值,一般以时间
  • 本文通过实例介绍了MySQL中的group_concat函数的使用方法,比如select group_concat(name) 。 MySQ
  • 1.GridView无代码分页排序:效果图:1.AllowSorting设为True,aspx代码中是AllowSorting="
  • 前言在本文中,我将展示如何将对象从一个图像添加到另一个图像。为此,我们需要:1.背景图像;2.对象3.对象的mask(mask为黑色,其他空
  • 这个标题念起来有点拗口,但却是理解数据结构的关键。标题中的4个术语,对应的英文分别是:shallow copy(注意,不是shadow co
  • 本文实例讲述了Golang最大递减数算法问题。分享给大家供大家参考,具体如下:给出一个非负整数,找到这个非负整数中包含的最大递减数。一个数字
  • 问题描述输入一串字符,由字母、数字和空格组成,长度 < 1000, 判断其中是否存在日期格式的数据。日期格式的数据具有如下的特征,连续
  • 场景:购物车增加商品数量同时更新bridge标志上的总商品个数,如果只是加上当前变化后的数量的话则之前原有的数量会被重新添加一遍造成计算错误
  • 简介Wikipedia、Facebook 和 Yahoo! 等主要 web 属性使用 LAMP 架构来为每天数百万的请求提供服务,而 Wor
手机版 网络编程 asp之家 www.aspxhome.com