• Golang函数相关


    函数定义

    Go语言中定义函数使用func关键字,具体格式如下:

    func 函数名(参数)(返回值){
        函数体
    }
    

    其中:

    函数名:由字母、数字、下划线组成。但函数名的第一个字母不能是数字。在同一个包内,函数名也称不能重名(包的概念详见后文)。
    参数:参数由参数变量和参数变量的类型组成,多个参数之间使用,分隔。
    返回值:返回值由返回值变量和其变量类型组成,也可以只写返回值的类型,多个返回值必须用()包裹,并用,分隔。
    函数体:实现指定功能的代码块。

    函数类型变量

    // 声明函数类型
    type fType func(int,int) int
    
    func add(a,b int) int {
    	return a + b
    }
    
    func sub(a, b int) int {
    	return a - b
    }
    
    // 函数类型变量使用测试
    func TestFunctionType(t *testing.T) {
    	var c fType
    	c = add
    	fmt.Println(c(1,2))
    	c = sub
    	fmt.Println(c(1,2))
    }
    

    函数作为参数传递

    // 函数作为参数
    func CallFunctionParameter(a,b int,c func(int,int) int) int {
    	return c(a,b)
    }
    
    // 参数传递函数测试
    func TestFunctionParameter(t *testing.T) {
    	fmt.Println(CallFunctionParameter(1,2,add))
    	fmt.Println(CallFunctionParameter(1,2,sub))
    }
    

    函数作为返回值

    func do(s string) (func(int,int) int,error) {
    	switch s {
    	case "+":
    		return add,nil
    	case "-":
    		return sub,nil
    	default:
    		err := errors.New("无法识别的操作符")
    		return nil,err
    	}
    }
    
    // 函数作为返回值测试
    func TestDo(t *testing.T) {
    	c,e := do("*")
    	if e != nil {
    		fmt.Println(e.Error())
    		return
    	}
    	fmt.Println(c(1,2))
    }
    

    匿名函数

    // 匿名函数 用于回调函数和闭包
    func TestAnonymous(t *testing.T) {
    	add := func(a,b int) {
    		fmt.Println(a +b)
    	}
    	add(1,2)
    
    	func(a,b int) {
    		fmt.Println(a+b)
    	}(1,2)
    }
    

    闭包函数

    // 闭包 闭包=函数+引用环境
    func adder() func(int) int {
    	var x int
    	return func(i int) int {
    		x += i
    		return x
    	}
    }
    
    // 闭包 进阶1
    func adder2(x int) func(int) int {
    	return func(y int) int {
    		x += y
    		return x
    	}
    }
    
    // 闭包进阶2 为文件名添加后缀
    func makeSuffixFunc(suffix string) func(string) string {
    	return func(name string) string {
    		// 判断是否不存在后缀
    		if !strings.HasSuffix(name,suffix) {
    			return name + suffix
    		}
    		return name
    	}
    }
    
    // 闭包进阶3 对参数进行运算
    func calc(base int) (func(int) int,func(int) int) {
    	add := func(i int) int {
    		base += i
    		return base
    	}
    
    	sub := func(i int) int {
    		base -= i
    		return base
    	}
    	return add,sub
    }
    
    // 闭包函数测试
    func TestClosure(t *testing.T) {
    	var f = adder()
    	fmt.Println(f(10)) // 10
    	fmt.Println(f(20)) // 30
    	fmt.Println(f(30)) // 60
    
    	f1 := adder()
    	fmt.Println(f1(30)) // 30
    
    	// 进阶1
    	f3 := adder2(10)
    	fmt.Println(f3(10)) // 20
    	fmt.Println(f3(20)) // 40
    
    	// 进阶2
    	jpgFunc := makeSuffixFunc(".jpg")
    	txtFunc := makeSuffixFunc(".txt")
    	fmt.Println(jpgFunc("test"))  // test.jpg
    	fmt.Println(txtFunc("test"))  // test.txt
    	fmt.Println(jpgFunc("test.jpg")) // test.jpg
    
    	// 进阶3 f4 add f5 sub
    	f4,f5 := calc(100)
    	fmt.Println(f4(10),f5(5)) // 110 105
    	fmt.Println(f4(5),f5(10)) // 110 100
    }
    

    Defer函数

    // defer 采用压栈 后入先出的方式 在函数返回时按照语句顺序逆序执行
    // 具有延迟调用特性,所以非常方便处理资源释放问题,如 资源清理、文件关闭、解锁及记录时间等
    // 在GO语言函数中return语句在底层并不是原子操作,分为赋值和RET指令两步,
    // defer语句执行时机在返回值赋值操作后,RET指令执行前
    func TestDefer(t *testing.T) {
    	fmt.Println("Start")
    	defer fmt.Println(1)
    	defer fmt.Println(2)
    	defer fmt.Println(3)
    	fmt.Println("End")
    }
    
    func f1() int {
    	x := 5
    	defer func() {
    		// defer在函数返回值赋值之后执行,所以无法改变返回值
    		x++
    	}()
    	return x
    }
    
    func f2() (x int) {
    	defer func() {
    		// defer操作直接修改了返回值变量,所以5变成6
    		x++
    	}()
    	return 5
    }
    
    func f3() (y int) {
    	x := 5
    	defer func() {
    		// defer在函数返回值赋值之后执行,函数返回时已经将x=5赋值给了返回值
    		// 如果将x++ 修改为 y++ 可以改变返回值
    		x++
    	}()
    	return x
    }
    
    func f4() (x int) {
    	defer func(x int) {
    		// defer在函数返回值赋值之后执行,函数返回时5赋值给了返回值
    		// 虽然此处貌似操作了返回变量x,但实际上操作的是defer参数中的x
    		x++
    		// 打印结果为多少?
    		// 答案是 1。 defer函数的参数在注册时就会执行运算确定值,所以刚开始x初始值为0。
    		fmt.Println(x)
    	}(x)
    	return 5
    }
    
    // Defer测试
    func TestDeferReturn(t *testing.T) {
    	fmt.Println(f1()) // 5
    	fmt.Println(f2()) // 6
    	fmt.Println(f3()) // 5
    	fmt.Println(f4()) // 5
    }
    
    func calcDefer(index string, a, b int) int {
    	ret := a + b
    	fmt.Println(index, a, b, ret)
    	return ret
    }
    
    // Defer输出测试
    func TestCalcDefer(t *testing.T) {
    	x := 1
    	y := 2
    	defer calcDefer("AA", x, calcDefer("A", x, y))
    	x = 10
    	defer calcDefer("BB", x, calcDefer("B", x, y))
    	y = 20
    	// 输出结果:
    	// A 1 2 3
    	// B 10 2 12
    	// BB 10 12 22
    	// AA 1 3 4
    	// 执行"A",参数x,y分别为1,2,所以输出 A 1 2 3,返回结果3作为参数传递给"AA"
    	// 执行"B",参数x,y分别为10,2,所以输出 B 10,2,12,返回参数12作为参数传递给"BB"
    	// 函数执行结束触发延迟函数,defer逆序执行
    	// 输出"BB" BB 10 12 22
    	// 输出"AA" AA 1  3  4
    }
    

    Panic/Recover

    // panic可以在任何地方引发,但recover只有在defer调用的函数中有效
    // recover()必须搭配defer使用
    // defer一定要在可能引发panic语句之前定义
    func panicTest() {
    	defer func() {
    		err := recover()
    		if err != nil {
    			fmt.Println("recover:",err)
    		}
    	}()
    	panic("Panic")
    }
    
    func TestPanicDemo(t *testing.T) {
    	panicTest()
    }
    

    练习题:分金币

    func TestDispathCion(t *testing.T) {
    	var (
    		coins = 50
    		users = []string{
    			"Matthew", "Sarah", "Augustus", "Heidi", "Emilie", "Peter", "Giana", "Adriano", "Aaron", "Elizabeth",
    		}
    		//map集合[string]:int 字符串:整型
    		//初始化一个集合,cap = users切片的长度
    		distribution = make(map[string]int, len(users))
    	)
    
    	for _,value := range users{
    		// 用户姓名统一转化小写
    		name := strings.ToLower(value)
    		distribution[value] += 1 * strings.Count(name,"e")
    		distribution[value] += 2 * strings.Count(name,"i")
    		distribution[value] += 3 * strings.Count(name,"o")
    		distribution[value] += 4 * strings.Count(name,"u")
    	}
    
    	for k,v := range distribution {
    		fmt.Println(k,"获得",v,"枚硬币。")
    		coins-=v
    	}
    	fmt.Println("剩下:",coins,"枚硬币。")
    }
    

    参考来源

  • 相关阅读:
    1216
    构建之法 1 2 3
    复利计算
    实验总结
    0916编译原理第二次上机作业
    0909第一次作业
    linux 更新jdk
    Java中使用OpenSSL生成的RSA公私钥进行数据加解密
    quartz定时任务时间表达式说明
    IntelliJ IDEA使用说明
  • 原文地址:https://www.cnblogs.com/hzpeng/p/15565595.html
Copyright © 2020-2023  润新知