defer测试

Sat, Jan 16, 2016
package main

import (
	"fmt"
	"sync"
	"testing"
)

//调用顺序
//最早调用的defer会在最后执行
func test0() {
	defer func() {
		fmt.Print("a\n")
	}()
	defer func() {
		fmt.Print("b")
	}()
	defer func() {
		fmt.Print("c")
	}()
	fmt.Println("test 0")
}

//defer是在函数结束后返回前被执行
//并且lambda闭包传的是值的引用
//也就是说如果返回值在函数定义时被命名,在defer调用的函数中就可以修改返回值
func test1() {
	doubleSum := func(x, y int) (z int) { //don't forget add () with return expression
		fmt.Printf("start:x(%p)=%d,y(%p)=%d,z(%p)=%d\n", &x, x, &y, y, &z, z)
		defer func() {
			fmt.Printf("defer:x(%p)=%d,y(%p)=%d,z(%p)=%d\n", &x, x, &y, y, &z, z)
			z = z * 2
		}()
		x = x * 2
		y = y * 2
		return x + y
	}
	fmt.Println("test 1")
	x, y := 10, 20
	z := doubleSum(x, y)
	fmt.Printf("x=%d,y=%d,z=%d\n", x, y, z)

}

// defer是在调用时传参,而不是在执行时传参
func test2() {
	otherDoubleSum := func(x, y int) (z int) { //don't forget add () with return expression
		defer func(ret int) {
			fmt.Printf("defer:x=%d,y=%d,z=%d\n", x, y, ret)
			ret = ret
		}(z) // 这个时候z的值是0而不是x+y
		x = x * 2
		y = y * 2
		return x + y
	}
	fmt.Println("test 2")
	x, y := 10, 20
	z := otherDoubleSum(10, 20)
	fmt.Printf("x=%d,y=%d,z=%d\n", x, y, z)
}

// 可以在defer的函数中捕获panic
func test3() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("panic: %s\n", err)
		}
	}()
	fmt.Println("test 3")
	panic("panic test!")
}

// 延迟调用中引发的错误,可被后续延迟调用捕获, 但仅仅最后一个panic会被捕获
func test4() {

	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("recover: %s\n", err)
		}
	}()
	defer func() {
		panic("defer panic")
	}()
	fmt.Println("test 4")
	panic("panic test!")
}

// defer的性能测试,开销不小
var lock sync.Mutex

func TestLock() {
	lock.Lock()
	lock.Unlock()
}

func TestDeferLock() {
	lock.Lock()
	defer lock.Unlock()
}

func BenchmarkTest(b *testing.B) {
	for i := 0; i < b.N; i++ {
		TestLock()
	}
}

func BenchmarkTestDefer(b *testing.B) {
	for i := 0; i < b.N; i++ {
		TestDeferLock()
	}
}

func main() {
	test0()
	test1()
	test2()
	test3()
	test4()
	// 性能测试跑的时间太长无法在play中
	//	fmt.Println(testing.Benchmark(BenchmarkTest))
	//	fmt.Println(testing.Benchmark(BenchmarkTestDefer))
}