• 狂神说Go语言学习笔记(四)


    狂神说Go语言学习笔记(一)
    狂神说Go语言学习笔记(二)
    狂神说Go语言学习笔记(三)

    一、什么是函数

    func main() {
    	//调用函数 函数名()
    	fmt.Println(add(1, 2)) //3
    }
    
    func add(a, b int) int {
    	c := a + b
    	return c
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9



    二、函数的声明

    func main() {
    	printinfo()
    
    	myprint("haha")
    
    	fmt.Println(add2(1, 2))
    
    	swap(1, 2)
    	
    }
    
    // 无参返回值函数
    func printinfo() {
    	fmt.Println("printinfo")
    }
    
    // 有一个参数的函数
    func myprint(msg string) {
    	fmt.Println(msg)
    }
    
    // 有两个参数的函数
    // 有一个返回值的函数
    func add2(a, b int) int {
    	c := a + b
    	return c
    }
    
    // 有多个返回值的函数
    func swap(a, b int) (int, int) {
    	return b, a
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32



    三、形式参数和实际参数

    // max 两个数字比大小
    // 形式参数:定义函数时,用来接收外部传入数据的参数,就是形式参数
    // 实际参数:调用函数时,传给形参的实际数据叫做实际参数
    func max(num1, num2 int) int {
    	var result int
    	if num1 > num2 {
    		result = num1
    	} else {
    		result = num2
    	}
    
    	//一个函数定义上有返回值,那么函数中必须使用return语句
    	//返回值
    	//调用处需要使用变量接受该结果
    	return result
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16



    四、可变参数

    概念:一个函数的参数类型确定,但是个数不确定,就可以使用可变参数

    func myfunc(arg ... int){}
    
    //arg ... int 告诉go这个函数接收不定数量的参数,类型全部都是int
    
    • 1
    • 2
    • 3
    func main() {
    	getSum(1, 2, 3, 4, 5, 6, 7, 100)
    }
    
    func getSum(nums ...int) {
    	sum := 0
    
    	for i := 0; i < len(nums); i++ {
    		fmt.Println(nums[i])
    		sum += nums[i]
    	}
    	fmt.Println("sum:", sum)
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述


    五、值传递和引用传递

    在这里插入图片描述

    值传递

    func main() {
    
    	//定义一个数组
    	arr1 := [4]int{1, 2, 3, 4}
    	fmt.Println("arr1默认数据", arr1)
    	update(arr1)
    	fmt.Print("arr1调用函数后数据", arr1)
    	//arr2的数据是从arr1复制来的,所以是不同的空间
    	//修改arr2并不会影响arr1
    	//值传递:传递的是数据的副本,修改数据,对于原始的数据没有影响
    	//值类型的数据,默认都是值传递,基础类型 array struct
    }
    
    func update(arr2 [4]int) {
    	fmt.Println("arr2接收数据", arr2)
    	arr2[0] = 10
    	fmt.Println("arr2修改后数据", arr2)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述
    在内存中:
    在这里插入图片描述
    值传递类型的改变的都是原先数据的副本,两份分别在不同的内存空间中!,所以修改 arr1 , arr2 不会改变!

    引用传递

    // 引用传递
    func main() {
    
    	//切片,可以扩容的数组
    	s1 := []int{1, 2, 3, 4}
    	fmt.Println("s1默认数据", s1)
    	update2(s1)
    	fmt.Print("s1调用函数后数据", s1)
    }
    
    func update2(s2 []int) {
    	fmt.Println("s2接收数据", s2)
    	s2[0] = 10
    	fmt.Println("s2修改后数据", s2)
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述
    在内存中:
    在这里插入图片描述
    s1 和 s2两个引用 都对同一片内存空间进行操作,改变s1 ,s2 当然也会变!


    六、函数变量的作用域

    在这里插入图片描述

    //全局变量
    var num int = 100
    func main() {
    	
    	//函数体内的局部变量
    	temp := 100
    	if b := 1 ; b<=10{
    		temp := 50
    		fmt.Println(temp)//局部变量,就近原则
    		fmt.Println(b)
    	}
    	fmt.Println(temp)
    	fmt.Println(num)
    }
    
    func f1()  {
    	a := 1
    	fmt.Println(a)
    	fmt.Println(num)
    }
    
    func f2()  {
    	b := 2
    	fmt.Println(b)
    	fmt.Println(num)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26



    七、递归函数

    在这里插入图片描述

    func main() {
    	fmt.Println(getSum1(5)) //15
    }
    
    func getSum1(n int) int {
    
    	if n == 1 {
    		return 1
    	}
    	return getSum1(n-1) + n
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11



    八、defer

    在这里插入图片描述

    func main() {
    	f("1")
    	fmt.Println("2")
    	defer f("3")
    	fmt.Println("4")    //1 2 4 3
    }
    
    func f(s string) {
    	fmt.Println(s)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    func main() {
    	f("1")
    	fmt.Println("2")
    	defer f("3")
    	fmt.Println("4")
    	defer f("5")
    	fmt.Println("6")
    	defer f("7")
    	fmt.Println("8")   //1 2 4 6 8 7 5 3
    }
    
    func f(s string) {
    	fmt.Println(s)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    func main() {
    	a := 10
    	fmt.Println("a=", a)
    	//参数已经传递过去了 在最后执行
    	defer f(a)
    	a++
    	fmt.Println("end a=", a)
    }
    
    func f(s int) {
    	fmt.Println("函数里面的a=", s)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12



    九、函数的本质

    // func() 本身就是一个数据类型
    func main() {
    
    	//f3 如果不加括号 函数就是个变量
    	//f3() 如果加了括号那就成了函数的调用
    	fmt.Printf("%T\n", f3) //func(int, int)
    
    	//定义函数类型的变量
    	var f5 func(int, int)
    	f5 = f3   //引用类型的
    	f5(1, 2)
    }
    
    func f3(a, b int) {
    	fmt.Println(a, b)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述



    十、匿名函数

    // 匿名函数
    func main() {
    	h1()
    	h2 := h1 //函数本身也是一个变量
    	h2()
    
    	//匿名函数
    	h3 := func() {
    		fmt.Println("我是h3函数")
    	}
    	h3()
    
    	x1 := func(a, b int) int {
    		fmt.Println(a, b)
    		return a + b
    		//fmt.Println("我是h4函数")
    	}(1, 2)
    
    	fmt.Println(x1)
    }
    
    func h1() {
    	fmt.Println("我是h1函数")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在这里插入图片描述


    十一、函数式编程

    在这里插入图片描述

    func main() {
    
    	r2 := oper(1, 2, add)
    	fmt.Println(r2) // 3
    	r3 := oper(1, 2, sub)
    	fmt.Println(r3) // -1
    	r4 := oper(8, 4, func(i int, i2 int) int {
    		if (i == 0) {
    			fmt.Println("除数不能为0")
    			return 0
    		}
    		return i / i2
    	})
    	fmt.Println(r4)  // 2
    }
    //高阶函数,可以接受一个函数作为一个参数
    func oper(a, b int, fun func(int, int) int) int {
    	r := fun(a, b)
    	return r
    }
    func add(a, b int) int {
    	return a + b
    }
    
    func sub(a, b int) int {
    	return a - b
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27



    十二、闭包

    /*
    一个外层函数中,有内层函数,该内层函数中,会操作外层函数的局部变量
    并且该外层函数的返回值就是这个内层函数
    这个内层函数和外层函数的局部变量,统称为闭包结构
    
    局部变量的生命周期就会发生改变 正常的局部变量会随着函数的调用而创建
    随着函数的结束而销毁 但是闭包结构中的外层函数的局部变量并不会随着外层函数的结束而销毁 因为内层函数还在使用
    */
    
    func main() {
    	r1 := increment()
    	fmt.Println(r1)  // 0x22e680
    
    	v1 := r1()
    	fmt.Println(v1) // 1
    
    	v2 := r1()
    	fmt.Println(v2) // 2
    
    	r2 := increment()
    	v3 := r2()
    	fmt.Println(v3) // 1
    }
    
    func increment() func() int {
    	//局部变量i
    	i := 0
    	//定义一个匿名函数,给变量自增并返回
    	fun := func() int {
    		i++
    		return i
    	}
    	return fun
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
  • 相关阅读:
    MyBatis - 参数传递
    unity无法激活认证、无法保存许可证、及unity package manager Error
    一文讲透为Power Automate for Desktop (PAD) 实现自定义模块 - 附完整代码
    Redis高频40问
    docker-compose:搭建酷炫私有云相册photoprism
    Java设计模式(上)
    柯桥日常口语学习|生活英语|实用口语口语天天练
    CSS的概念和基本用法
    同一个线程池执行不同类型的任务
    Python之哈希表-哈希表原理
  • 原文地址:https://blog.csdn.net/G823909/article/details/128135578