广告位联系
返回顶部
分享到

go的defer和return的执行顺序介绍

Golang 来源:互联网 作者:佚名 发布时间:2024-07-14 08:58:21 人浏览
摘要

go的defer和return的执行顺序 go的defer和return是golang中的两个关键字,return用于返回函数的返回值,也可以参与一定的流程控制,比如下面代码,return短路了后面的输出 1 2 3 4 5 6 7 8 9 10 11 12 13 14

go的defer和return的执行顺序

go的defer和return是golang中的两个关键字,return用于返回函数的返回值,也可以参与一定的流程控制,比如下面代码,return短路了后面的输出

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

package main

 

import "fmt"

 

// defer 和 return的详解

func main() {

    foo(2)

    foo(1)

}

func foo(i int) {

    fmt.Println(i)

    if i == 1 {

        return

    }

    fmt.Println(i + 1)

}

结果:

2
3
1

第一次输出完整的输出了i和i+1,第二次输出被短路,只输出了1

defer是golang中的延迟调用,经常用于文件流的关闭,锁的解锁操作,defer后面的操作会在当前函数或者goroutine结束之后进行调用

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

package main

 

import "fmt"

 

// defer 和 return的详解

func main() {

    foo()

}

func foo() {

    defer fmt.Println("println defer")

    fmt.Println("println foo")

}

 

输出:

println foo

println defer

defer自身有一些特性,比如defer和defer之间的执行顺序是先进后出,先defer的最后执行,分析下面代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

package main

 

import "fmt"

 

// defer 和 return的详解

func main() {

    foo()

}

func foo() {

    defer fmt.Println("floor 3")

    defer fmt.Println("floor 2")

    fmt.Println("floor 1")

}

 

输出:

floor 1

floor 2

floor 3

根据这一特性,如果我们defer调用的代码中存在panic 的可能性,为了保证系统的运行,我们应该在前面recover而不是后面

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

ackage main

 

import "fmt"

 

// defer 和 return的详解

func main() {

    foo()

}

func foo() {

    defer func() {

        panic("panic test")

    }()

    defer func() {

        if err := recover(); err != nil {

            fmt.Println("catch panic:", err)

        }

    }()

}

 

输出:

panic: panic test

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

package main

 

import "fmt"

 

// defer 和 return的详解

func main() {

    foo()

}

func foo() {

    defer func() {

        if err := recover(); err != nil {

            fmt.Println("catch panic:", err)

        }

    }()

    defer func() {

        panic("panic test")

    }()

}

输出:

catch panic: panic test

defer和return的相互影响

defer和return的相互影响,主要是在返回值上表现,考虑下面代码,输出应该是什么:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

import "fmt"

 

// defer 和 return的详解

func main() {

    fmt.Println(foo1())

    fmt.Println(foo2())

    fmt.Println(foo3())

}

func foo1() int {

    i := 1

    defer func() { i++ }()

    return i

}

func foo2() (i int) {

    i = 1

    defer func() { i++ }()

    return i

}

func foo3() (i int) {

    defer func() { i++ }()

    return 1

}

输出:

1
2
2

导致上面情况的原因是

在 foo1 函数中,defer 语句中的闭包会在函数返回后执行,但是此时返回值已经确定为 1 ,所以最终返回 1 。

在 foo2 函数中,使用了命名返回值 i 。defer 语句中的闭包修改的是这个命名返回值,所以返回 2 。

在 foo3 函数中,同样使用了命名返回值 i ,defer 语句中的闭包修改了这个命名返回值,并且函数直接返回 1 ,但 defer 中的修改使得最终返回 2 。

而return的另一个特性,也会影响return和defer中代码的执行顺序

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

package main

 

import "fmt"

 

// defer 和 return的详解

func main() {

    fmt.Println(foo1())

 

}

func foo1() int {

    defer func() { fmt.Println("This is defer") }()

    return func() int {

        fmt.Println("This is return")

        return 1

    }()

}

 

输出:

This is return

This is defer

1

导致上面输出的原因是,return是非原子性的,defer会在return返回值之前执行,但return中的语句,会被全部执行,直到return锚定了某个值或者命名返回值,然后执行defer语句,最后返回return锚定的这个值


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 :
相关文章
  • Go中gin框架的*gin.Context参数常见实用方法
    梗概: *gin.Context是处理HTTP请求的核心。ctx代表context(上下文),它包含了处理请求所需的所有信息和方法,例如请求数据、响应构建器、
  • Python实现图像添加水印的方法
    在日常图像处理中,为图片添加水印是一项常见任务。有多种方法和工具可供选择,而今天我们将专注于使用Python语言结合PIL库批量添加水
  • go的defer和return的执行顺序介绍
    go的defer和return的执行顺序 go的defer和return是golang中的两个关键字,return用于返回函数的返回值,也可以参与一定的流程控制,比如下面代码
  • 使用go语言实现Redis持久化的代码
    redis是一个内存数据库,如果你把进程杀掉,那么里面存储的数据都会消失,那么这篇文章就是来解决redis持久化的问题 我们在redis.conf文件
  • Go中的Timer和Ticker介绍
    一:简介 在日常开发中,我们可能会遇到需要延迟执行或周期性地执行一些任务。这个时候就需要用到Go语言中的定时器。 在Go语言中,定
  • Golang在gin框架中使用JWT鉴权
    什么是JWT JWT,全称 JSON Web Token,是一种开放标准(RFC 7519),用于安全地在双方之间传递信息。尤其适用于身份验证和授权场景。JWT 的设计
  • Golang使用Redis与连接池方式
    Golang使用Redis与连接池 使用下载go的redis包go get github.com/gomodule/redigo/redis 如果网不好的话就很费劲了 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 2
  • Golang使用embed引入静态文件的代码
    Go 语言从 1.16 版本开始引入了一个新的标准库embed,可以在二进制文件中引入静态文件 指令:/go:embed 通过一个简单的小实例,来演示将静态
  • Golang发送Get和Post请求的实现
    最近在研究钉钉机器人,发现钉钉的第三方接口有时需要用Get或者Post请求访问,虽然说可以通过Apifox直接模拟发送请求,但是我还是想研究
  • Go实现数据脱敏的方案设计
    在一些常见的业务场景中可能涉及到用户的手机号,银行卡号等敏感数据,对于这部分的数据经常需要进行数据脱敏处理,就是将此部分数
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计