内容简介: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 函数返回值的栈空间与执行顺序
- golang 的返回值是通过栈空间,不是通过寄存器,这点最重要。调用函数前,首先分配的是返回值空间,然后是入参地址,再是其他临时变量地址。
-
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分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 使用动态分析技术分析 Java
- 使用动态分析技术分析 Java
- 案例分析:如何进行需求分析?
- 深度分析ConcurrentHashMap原理分析
- 如何分析“数据分析师”的岗位?
- EOS源码分析(3)案例分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
MySQL权威指南
Randy Jay Yarger / 林琪、朱涛江 / 中国电力出版社 / 2003-11-1 / 49.00元
为一种开源数据库,MySQL已经成为最流行的服务器软件包之一。开发人员在其数据库引擎中提供了丰富的特性(只需很少的内存和CPU支持)。 因此,众多Linux和Unix服务器(以及一些Windows服务器)都采用MySQL作为其数据库引擎。由于MySQL作为Web站点后端时速度特别快而且相当方便,所有在目前流行的一个词LAMP(表示Linux、Apache、MySQL和Perl、Python或......一起来看看 《MySQL权威指南》 这本书的介绍吧!