zoukankan      html  css  js  c++  java
  • 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,"枚硬币。")
    }
    

    参考来源

  • 相关阅读:
    JZOJ 3034. 【NOIP2012模拟10.17】独立集
    JZOJ 3035. 【NOIP2012模拟10.17】铁轨
    JZOJ 1259. 牛棚安排
    数位DP JZOJ 3316. 非回文数字
    JZOJ 3046. 游戏
    JZOJ 3013. 填充棋盘
    debian 安装oracle提供的java8
    java 汉字转拼音 PinYin4j
    debian ssh设置root权限登陆 Permission denied, please try again
    java并发下订单生成策略
  • 原文地址:https://www.cnblogs.com/hzpeng/p/15565595.html
Copyright © 2011-2022 走看看