当前位置: 首页 > news >正文

什么是网站流量优化做网站的像素

什么是网站流量优化,做网站的像素,国家企业信息信用公信系统,资中做网站多少钱defer延迟机制 defer是什么 defer是go中一种延迟调用机制。 执行时机 defer后面的函数只有在当前函数执行完毕后才能执行。 执行顺序 将延迟的语句按defer的逆序进行执行,也就是说先被defer的语句最后被执行,最后被defer的语句,最先被执…

defer延迟机制

defer是什么

defer是go中一种延迟调用机制。

执行时机

defer后面的函数只有在当前函数执行完毕后才能执行。

执行顺序

将延迟的语句按defer的逆序进行执行,也就是说先被defer的语句最后被执行,最后被defer的语句,最先被执行,通常用于释放资源。

多个defer本质就是用栈存储,先进后出。

defer定义

//最后不要忘记函数调用
//使用匿名函数
defer func (形参列表){}(实参)//最后不要忘记调用函数
//使用事先声明的函数
defer 函数名(实参)//最后不要忘记调用方法
defer 方法名(形参列表){}(实参)

defer的功能一般是用于释放资源。

defer后面的函数是可以有返回值的,但是一般没有作用。

注意事项

方法或函数必需调用

//报错:未调用函数
defer func(){fmt.Println("a")
}

注意声明顺序

虽然defer的执行时机在函数结束后,但是声明的时候使用的变量或者参数得是函数内在defer声明之前就定义好的。

//报错:student未定义
defer student.GetName(2)
var student Student//报错:age未定义
defer func(a int){fmt.Printf("年龄为%d\n",age)
}(age)
age := 15

多个defer的执行顺序

多个defer出现的时候,它会把defer之后的函数压入一个栈中延迟执行,也就是先进后出(LIFO).

写在前面的defer会比写在后面的defer调用的晚。下面通过一个示例看一下:

package defer_knowledgeimport "fmt"type Student struct{Name string
}func (s Student) GetName(n int){fmt.Printf("这是第%d个defer\n",n)
}func sayHello(n int){fmt.Printf("这是第%d个defer\n",n)
}//验证defer的执行顺序
func DeferFirst(){fmt.Println("hello world")var age int = 25defer func (){fmt.Println("我是第1个defer")}()age++/*虽然defer的执行时机在return之后但是声明defer时,结构体实例要先声明,否则无法访问结构体实例方法*/var student Studentdefer student.GetName(2)defer func (){fmt.Println("我是第3个defer")}()defer sayHello(4)
}

结果

这是第4个defer
我是第3个defer
这是第2个defer
我是第1个defer

图示
在这里插入图片描述

延迟参数传入时机

基本语法

注意事项

defer函数的入参参数是在defer函数声明时决定的。例如

package defer_knowledgeimport "fmt"//defer的参数是声明时传入的
func DeferParams(){var age = 10defer func(a int){fmt.Printf("defer内的参数为%d\n",a)}(age)age = 25fmt.Printf("age已经变成了%d\n",age)
}

调用结果

age已经变成了25
defer内的参数为10

小结

值类型

所以我们要注意传入的参数,

【值类型参数】
值类型参数原始变量改变不影响传入参数,例如int、数组、结构体
如果我们想要defer执行时能读取到变化后的"值类型"参数,可以传入指针

例如

package defer_knowledge
import "fmt"
//defer的参数是声明时传入的
func DeferParams(){var age = 10//如果想要追踪值类型的变化可以传入值类型指针defer func(a *int){fmt.Printf("最初如果传入指针,defer内参数为%d\n",*a)}(&age)defer func(a int){fmt.Printf("defer内的参数为%d\n",a)}(age)age = 25fmt.Printf("age已经变成了%d\n",age)
}

调用结果

age已经变成了25
defer内的参数为10
最初如果传入指针,defer内参数为25
引用类型

具体看引用的底层是否发生变换,例如切片,如果没发生扩容将使用相同的。

package defer_knowledge
import "fmt"
func DeferParams2(){var arr = make([]int,5,5)//引用类型直接传递即可,将追踪到引用改变为止defer func(a []int){fmt.Printf("defer内的参数为%#v\n",a)}(arr)arr[2] = 10fmt.Printf("arr已经变成了%#v\n",arr)
}

调用结果

arr已经变成了[]int{0, 0, 10, 0, 0}
defer内的参数为[]int{0, 0, 10, 0, 0}

声明时机和执行时机

声明时机

defer的声明时机时按照他出现在代码中的顺序,这时会执行两个操作。

1.传入参数
2.检查内部要访问的变量是否已经定义

举例

func DeferTime(){var age int/*声明时会传入参数,以及检查内部逻辑是否正确*/defer func(){//注意,这个不是defer函数的参数//和常规变量作用域一样,本层找不到就去外面找age++}()
}

错误示范

func DeferTime(){defer func(){//报错:age未定义age++}()var age int
}

执行时机

defer的执行时机是在函数逻辑结束后,或者说return后,按照defer栈调用。

举例

func DeferTime2(){var age int defer func(){//按照defer栈,此时访问到的age为 11age = age+5fmt.Printf("age的值为%d\n",age)}()defer func(){//defer执行时机为函数结束后,所以此时访问到的 age = 10age++fmt.Printf("age的值为%d\n",age)}()age = 10
}

结果

age的值为11
age的值为16

defer与return的区别

图示

在这里插入图片描述

可以看到 return 执行的时候,并不是原子性操作,一般是分为两步:将结果x赋值给了返回值,然后执行了RET指令;而defer语句执行的时候,是在赋值变量之后,在RET指令之前。所以这里注意一下。返回值和x的关系。如果x是一个值类型,这里是进行了拷贝的。

执行图示意

在这里插入图片描述

函数返回值

不具名返回

形式

func 函数名(参数列表) 返回值类型{return 返回值
}//例如
/*return sum操作拆解:实际对外暴露返回值为 sum_copysum_copy = sum所以return实际执行拷贝操作,他不是将函数内的变量抛出,而是将拷贝后的值抛出
*/
func Add(a,b int) int{sum := a+breturn sum
}

案例1

func DeferAndReturn1() int{var num intdefer func(){num++//num的值为16fmt.Printf("num的值为%d\n",num)}()num = 15return num
}//调用
target := DeferAndReturn1()
//target的值为15
fmt.Printf("target的值为%d\n",target)

解析

func DeferAndReturn1() int{var num intdefer func(){num++//num的值为16fmt.Printf("num的值为%d\n",num)}()num = 15/*实际操作copy_num = num对外暴露copy_num,由于num是值类型,所以后续defer中对num的操作不影响copy_num*/return num
}

误区1

想到了指针操作,但是理解出错。

func DeferAndReturn1() int{var num intvar ptr = new(int)ptr = &numdefer func(){*ptr++//num的值为16fmt.Printf("num的值为%d\n",num)}()num = 15return num
}
//调用
target := DeferAndReturn1()
//target的值为15
fmt.Printf("target的值为%d\n",target)

原因:

func DeferAndReturn1() int{var num intvar ptr = new(int)ptr = &numdefer func(){*ptr++//num的值为16fmt.Printf("num的值为%d\n",num)}num = 15/*实际操作copy_num = num对外暴露copy_num,我们修改通过指针ptr修改num的值,还是没影响到copy_num*/return num
}

正确思维

func DeferAndReturn1() *int{var num intvar ptr = new(int)ptr = &numdefer func(){num++//num的值为16fmt.Printf("num的值为%d\n",num)}()num = 15return ptr
}
//调用
target := DeferAndReturn1()
//target的值为16
fmt.Printf("target的值为%d\n",*target)

结果

num的值为16
target的值为16

原因

func DeferAndReturn1() *int{var num intvar ptr = new(int)ptr = &numdefer func(){num++//num的值为16fmt.Printf("num的值为%d\n",num)}()num = 15/*实际操作copy_ptr = ptr由于ptr是引用类型,所以defer对ptr的影响会影响到copy_ptrnum的本质就是*ptr,操作num就是在操作ptr*/return ptr
}
具名返回

相当于实际要暴露的返回值早就确定好了,return只是起到一个结束函数的作用。

func 函数名(参数列表)(返回值 返回值类型){return
}//示例
/*sum就是实际暴露的返回值,且已经声明了
*/
func Add(a,b int) (sum int){return
}

案例1

func DeferAndReturn2() (num int){defer func(){num++}()num = 10return
}num2 := DeferAndReturn2()
fmt.Printf("外部num的值为%d\n",num2)

结果

外部num的值为11

原因

func DeferAndReturn2() (num int){defer func(){num++}()num = 10/*这里写return 和 return num一样最终暴露的值为 num所以defer中对num的操作会影响到最终返回值*/return
}
http://www.dtcms.com/a/616808.html

相关文章:

  • 滨州网站建设 中企动力wordpress 分类过滤
  • 贵阳市 网站建设指定词整站优化
  • 广东汇鑫科技网站建设网站建设验收报告模板
  • 笔记本网站开发背景鹤城建设集团网站
  • 上海营销型企业网站上门做网站公司哪家好
  • 微信网站开发详解百度热度榜搜索趋势
  • wordpress网站制作网站布局选择
  • 企业网站备案资料样本杭州协会网站建设方案
  • 做网站界面一般用什么来做网站备案各种问题汇总
  • 竹山县住房和城乡建设局网站电子商务网站规划与建设
  • 网站标题算关键词优化吗chatgpt 在线
  • 做企业福利网站起名wordpress 首页 404
  • 做网站编程序在线设计平台怎么运营
  • 泉州英文网站建设wordpress 同步 博客园
  • 网站建设中服务器搭建方式网站系统的软件和硬件接口
  • 网站关键词怎么修改做网站编辑好还是期刊编辑好
  • 查询优惠券的网站如何做微信编辑器做网站
  • 建设 银行网网站浙江响应式网站建设
  • 企业培训网站wordpress 手机端打开速度慢
  • 国外被动收入网站做的好的帮卖货平台
  • 顺德公司网站制作大连建设工程信息网档案下载
  • 中国平面设计和网站建设WordPress连接微博
  • 广州公司建站网站开发建设合同
  • 网站反链暴增怎么回事网站开发用框架开发的优缺点
  • 手机建个人网站怎么建设一个网站赚钱
  • 企业网站首页设计求个没封的w站2021你懂
  • 电子商城网站开发文档机械设计最好的三维软件
  • 移动网站开发教程做网站一定要备案吗
  • 1280的界面网站做多宽太原手手工网站建设公司
  • 一元购网站的建设你做的网站可视区域多少钱