Go defer分析

栏目: Go · 发布时间: 6年前

内容简介:A "defer" statement invokes a function whose execution is deferred to the moment the surrounding function returns, either because the surrounding function executed a通过使用为什么输出的是"Hello": 在 defer 中, fmt.Print 被推迟到函数返回后执行,可是 m.print() 的值在当时就已经被求出,因此, m.print(

什么是defer

A "defer" statement invokes a function whose execution is deferred to the moment the surrounding function returns, either because the surrounding function executed a return statement , reached the end of its function body , or because the corresponding goroutine is panicking .

通过使用 defer 修饰一个函数,使其在外部函数返回后才被执行,一种是因为周围的函数执行了一个 return 语句,到达了它的函数体的末尾,另一种是因为相应的goroutine是 panicking

先看example1

package main

import "fmt"

func main()  {
    data1 := example1()
    fmt.Printf("output1:%v\n", data1)
    data2 := example2()
    fmt.Printf("output2:%v\n", data2)
    data3 := example3()
    fmt.Printf("output3:%v\n", data3)
}

func example1() (result int) {
    defer func() {
        result++
    }()
    return 0
}
func example2() (r int) {
    t := 1
    defer func() {
        t = t + 1
    }()
    return t
}
func example3() (r int) {
    defer func(r int) {
        r = r + 1
    }(r)
    return 1
}
//output1:1
//output2:1
//output3:1

go 函数返回值的栈空间与执行顺序

  1. golang 的返回值是通过栈空间,不是通过寄存器,这点最重要。调用函数前,首先分配的是返回值空间,然后是入参地址,再是其他临时变量地址。
  2. return 是非原子的,return 操作的确是分三步:
     将返回值拷贝到栈空间第一块区域,即:返回值 = x
     执行defer 操作, 即: 调用defer函数
     RET 跳转, 即:返回
    这个操作的确是可以对应到汇编代码的。

example4

package main

import "fmt"

type message struct {
    content string
}

func (p *message) set(c string) {
    p.content = c
}

func (p *message) print() string {
    return p.content
}

func main()  {

    m := &message{content: "Hello"}

    defer fmt.Println(m.print())        //m.print()  == "Hello", 将值拷贝进去

    m.set("World")
}

//输出:Hello

为什么输出的是"Hello": 在 defer 中, fmt.Print 被推迟到函数返回后执行,可是 m.print() 的值在当时就已经被求出,因此, m.print() 会返回 "Hello" ,这个值会保存一直到外围函数返回。

example4 改进

package main

import "fmt"

type message struct {
    content string
}

func (p *message) set(c string) {
    p.content = c
}

func (p *message) print() string {
    return p.content
}

func main()  {

    m := &message{content: "Hello"}

    defer func() {
        fmt.Println(m.print())
    }()

    m.set("World")
}

//输出:World

对 m 地址的引用

example 5

package main

import (
    "errors"
    "fmt"
    "io"
)

type reader struct{}

func (r reader) Close() error {
    return errors.New("Close Error")
}


func release(r io.Closer) (err error)  {

    defer func() {
        if err := r.Close(); err != nil{
            fmt.Println("my errors")
        }
    }()

    return
}

func main()  {

    r := reader{}

    err := release(r)

    fmt.Println(err)
}
//输出:my errors
//输出:<nil>

example 5改进

package main

import (
    "errors"
    "fmt"
    "io"
)

type reader struct{}

func (r reader) Close() error {
    return errors.New("Close Error")
}


func release(r io.Closer) (err error)  {

    defer func() {
        if err = r.Close(); err != nil{
            fmt.Println("my errors")
        }
    }()

    return
}

func main()  {

    r := reader{}

    err := release(r)

    fmt.Println(err)
}

//输出: my errors
//输出:Close Error

因为变量的作用域不同导致的块级屏问题。将 err := r.Close() 改成 err = r.Close 即可。

example 6 忽略了错误

func do() error {
    f, err := os.Open("book.txt")
    if err != nil {
        return err
    }
    defer f.Close()

    // ..code...

    return nil
}

example 6 改进

func do() (err error) {
    f, err := os.Open("book.txt")
    if err != nil {
        return err
    }

    defer func() {
        if ferr := f.Close(); ferr != nil {
            err = ferr
        }
    }()

    // ..code...

    return nil
}

以上所述就是小编给大家介绍的《Go defer分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Data Structures and Algorithm Analysis in Java

Data Structures and Algorithm Analysis in Java

Mark A. Weiss / Pearson / 2011-11-18 / GBP 129.99

Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course wa......一起来看看 《Data Structures and Algorithm Analysis in Java》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具