MST

星途 面试题库

面试题:Go语言defer在函数调用与错误处理中的执行顺序

给定如下Go语言代码: ```go package main import ( "fmt" ) func test() (int, error) { var num int defer func() { num++ fmt.Println("defer1") }() defer func() { num = num + 2 fmt.Println("defer2") }() err := fmt.Errorf("some error") return num, err } func main() { result, err := test() if err != nil { fmt.Println(err) } fmt.Println("result: ", result) } ``` 1. 请预测程序的输出结果,并解释defer在这种函数返回值与错误处理场景下的执行顺序和对返回值的影响。 2. 如果将 `return num, err` 这行代码拆分为 `return num` 和 `return err` (当然这种写法在语法上不允许,假设可以这么写,且后者返回时num值会延续前者执行后的结果),输出结果会有什么变化,为什么?
38.6万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 预测输出结果及解释
    • 输出结果为:
      defer2
      defer1
      some error
      result:  3
      
    • defer执行顺序:在Go语言中,defer语句会在函数返回前按后进先出(LIFO)的顺序执行。这里先定义了两个defer语句,所以defer func() { num = num + 2; fmt.Println("defer2") }() 会在 defer func() { num++ ; fmt.Println("defer1") }() 之前执行。
    • 对返回值的影响:Go语言的函数返回值在执行到return语句时会创建一个返回值的副本(如果有命名返回值,会先将命名返回值赋值给副本)。这里num是命名返回值,在执行return num, err时,num的值0被复制到返回值副本中。然后defer语句按顺序执行,先执行num = num + 2num变为2,再执行num++num变为3。但返回值副本在return语句执行时已确定,所以最终返回的num值是0,经过defer修改后的num值3不会影响最初确定的返回值副本。不过在main函数中打印result时,它获取的是命名返回值num最终的值3(因为命名返回值在函数结束时保存了最后修改的值),而错误err则正常返回并被main函数捕获打印。
  2. 假设拆分return的输出结果及原因
    • 假设可拆分为return numreturn err,输出结果为:
      defer2
      defer1
      some error
      result:  1
      
    • 原因:当执行return num时,num值为0,按defer的LIFO顺序,先执行defer func() { num = num + 2; fmt.Println("defer2") }()num变为2,再执行defer func() { num++ ; fmt.Println("defer1") }()num变为3。但此时函数已返回num值0,num后续的修改不会影响已返回的值。当执行return err时,只是返回错误,不会影响result的值。而在main函数中打印result时,由于return num已返回0,后续num的修改不影响result,所以result为0经过第一个defer语句修改后的1(因为第一个defer先执行num = num + 2,但返回值已确定为0,第二个defer num++对返回值无影响,而在main函数获取命名返回值num时,它经过了第一个defer的修改)。