Go函数详解

什么是函数

  • 函数是基本的代码块,用于执行一个任务
  • Go语言最少有个main()函数
  • 你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务
  • 函数声明告诉了编译器函数的名称,返回类型和参数
package main

import "fmt"

// func定义  一个add的函数  (定义两个变量 int型)   返回值类型为int
//
func add(a, b int) int {
   c := a + b
   //设置返回值为c
   return c
}

func main() {
   //调用函数 add的方法  打印输出
   fmt.Println(add(1, 2))
}

函数的声明

Go语言函数定义格式如下:

  • 无参无返回值函数
  • 有一个参数的函数
  • 有两个参数的函数
  • 有一个返回值的函数
    • 有多个返回值的函数
package main

import "fmt"

func main() {
   //函数的调用  - 无参无返回值函数
   printfinfo()

   //- 有一个参数的函数
   msg := "didididi"
   myprint(msg)

   // - 有一个参数的函数
   num := add2(1, 2)
   fmt.Println(num)

   //- 有多个返回值的函数
   a := "狂神说"
   b := "学相伴"
   fmt.Println(add3(a, b))
}

// - 无参无返回值函数
func printfinfo() {
   fmt.Println("hello,学相伴")
}

// - 有一个参数的函数
func myprint(str string) {
   fmt.Println(str)
}

// - 有两个参数的函数
// - 有一个返回值的函数
func add2(a, b int) int {
   c := a + b
   //设置返回值为c
   return c
}

// - 有多个返回值的函数
func add3(x, y string) (string, string) {

   //设置返回值为c
   return y, x
    /*
    输出结果:
    hello,学相伴
	didididi
	3
	学相伴 狂神说

    */
}
package main

func main() {
   //实际参数:调用函数时,传给形参实际数据叫做实际参数-num1,num2
   max(1, 2)
}

// 形式参数:定义函数时,用来接收外部传入数据的参数-num1,num2
func max(num1, num2 int) {

}

可变参数

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

package main

import "fmt"

func main() {
   getSum(1, 2, 4, 5, 100)
}

// 定义一个求和函数getsum方法  定义一个可变参数num
func getSum(num ...int) {
   sum := 0
   for i := 0; i < len(num); i++ {
      //遍历输出每一个传递的值
      fmt.Println(num[i])

      //sum=sum+num[i]
      sum += num[i]
   }
   fmt.Printf("求和函数:sum=%d", sum)
}
/*
输出结果:
1
2
4
5
100
求和函数:sum=112

*/

注意事项:

  • 如果一个函数的参数时可变参数,同时还有其他的参数,可变参数要放在列表的最后
  • 一个函数的参数列表最多只能有一个可变参数

参数传递

按照数据的存储特点来分:

  • 值类型的数据:操作的是数据本身、int .string、bool、float64、array...
  • 引用类型的数据:操作的是数据的地址slice、map、 chan....

值传递

package main

import "fmt"

func main() {
   // 定义一个数组 [个数] 类型 {}
   arr := [4]int{1, 2, 3, 4}
   fmt.Println(arr)
   update(arr)
   fmt.Println("调用修改后的数据", arr)
}
func update(arr2 [4]int) {
   fmt.Println("arr接受的数据", arr2)
   arr2[0] = 100
   fmt.Println("arr修改后的数据", arr2)
}
/*
输出结果:
[1 2 3 4]
arr接受的数据 [1 2 3 4]
arr修改后的数据 [100 2 3 4]
调用修改后的数据 [1 2 3 4]

*/

引用传递

package main

import "fmt"

func main() {
   // 切片 可以扩容的数组
   s1 := []int{1, 2, 3, 4}
   fmt.Println("默认的数据", s1)
    //传入的是引用类型的数据,地址
   update2(s1)
   fmt.Println("调用后的数据", s1)
}

func update2(s2 []int) {
   fmt.Println("传递后的数据", s2)
   s2[0] = 100
   fmt.Println("修改后的数据", s2)
}

函数中变量的作用域

作用域:变量可以使用的范围

局部变量:函数内部定义的变量,叫做局部变量

全部变量:函数外部定义的变量,叫做全局变量

package main

import "fmt"

// 全局变量  整个类都可以使用
var num int = 30

func main() {
   // 局部变量 temp 只能在temp方法中使用
   temp := 100

   if b := 1; b < 10 {
      temp := 30
      fmt.Println("局部变量b:", b)
      fmt.Println("局部变量temp:", temp)
   }
   fmt.Println(temp)

   // 调用f1,f2方法
   f1()
   f2()
}
func f1() {
   fmt.Println(num)
}
func f2() {
   fmt.Println(num)
}

递归函数

定义:一个函数自己调用自己,就叫递归函数

注意:递归函数需要有一个出口,逐渐向出口靠近,没有出口就会形成死循环

package main

import "fmt"

func main() {
   //创建一个对象,接受返回值
   sum:= getsum (5)
   
   //打印输出求和的值
   fmt.Println(sum)
}

   //创建一个求和函数  getsum (参数  类型)  返回值类型
func getsum(n int) int {
   if n == 1 {
      return 1
   }
   return getsum(n-1) + n
}

defer

语义:推迟、延迟

在go语言中,使用defer关键字来延迟一个函数或者方法的执行

package main

import "fmt"

func main() {

   f("1")
   f("2")
   defer f("3")
   f("4")
}
func f(s string) {
   fmt.Println(s)
}

defer函数或者方法:一个函数或方法的执行被延迟了

  • 你可以在函数中添加多个defer语句,当函数执行到最后时,这些defer语句会按照逆序执行,最后该函数返回,特别是当你在进行一些打开资源的操作时,遇到错误需要提前返回,在返回前你需要关闭相应的资源,不然很容易造成资源泄露等问题
  • 如果有很多调用defer,那么defer是采用后进先出〈栈)模式。
package main

import "fmt"

func main() {

   f("1")
   f("2")
   defer f("3")
   f("4")
   defer f("5")
   f("6")
   defer f("7")
   f("8")
}
func f(s string) {
   fmt.Println(s)
}
/*
输出结果:
1
2
4
6
8
7
5
3
*/

image-20221116164255326

高级:函数的数据类型

package main

import "fmt"

// fun 本身就是一个数据类型
func main() {
   //ff如果不加括号,函数就是一个变量
   //ff()如果加了括号那就变成了函数的调用
   fmt.Printf("%T\n", ff)
   //fmt.Printf("\n%T", 10) //int
   //fmt.Printf("\n%T", "dupeng") //string

   //定义函数的比那里
   var f5 func(int, int)
   f5 = ff //引用类型   将ff函数---变量赋值给f5
   fmt.Println(f5)
   fmt.Println(ff)
}

func ff(a, b int) {
   fmt.Println(a, b)
}

函数在Go语言中是复合类型,可以看做是一种特殊的变量。

函数名()︰调用返回结果
函数名:指向函数体的内存地址,一种特殊类型的指针变量

高级:匿名函数

package main

import "fmt"

func main() {
   //调用fq函数
   fq()

   //函数不加括号为变量
   fw := fq

   // 加了括号时为函数的调用
   fw()
   //=========================================================
   // 注意匿名函数创建需要在函数内
   //创建一个匿名函数  将匿名函数赋值给fe
   fe := func() {
      fmt.Println("我是fe函数")
   }
   //调用一下fe函数
   fe()
   //=========================================================
   // 匿名函数自己调用自己
   func(a, b int) {
      fmt.Println(a, b)
   }(1, 2)
   //=========================================================
   // 匿名函数传返回值  r1 来接受返回值
   r1 := func(a, b int) int {

      fmt.Println("我是匿名函数")
      return a + b
   }(1, 2)
   fmt.Println(r1)
}

func fq() {
   fmt.Println("我是fq函数")
}

Go语言是支持函数式编程:
1、将匿名函数作为另外一个函数的参数,回调函数
2、将匿名函数作为另外一个函数的返回值,可以形成闭包结构

高级:回调函数

高阶函数:根据go语言的数据类型的特点,可以将一个函数作为另外一个函数的参数。fun1(), fun2()
将fun1函数作为fun2这个函数的参数
fun2函数:就叫做高阶函数,接收了一个函数作为参数的函数

fun1函数:就叫做回调函数,作为另外—个函数的参数

package main

import "fmt"

func main() {
   f1 := addd(1, 2)
   fmt.Println(f1)

   r2 := oper(3, 4, addd)
   fmt.Println(r2)

   r4 := oper(3, 4, sub)
   fmt.Println(r4)

   r5 := oper(8, 4, func(i int, i2 int) int {
      if i2 == 0 { //除数不能为0
         fmt.Println("除数不能为0")
         return 0
      }
      return i / i2

   })
   fmt.Println(r5)
}

// 高阶函数 oper   传入两个int类型的x,y   和传入一个命名为fun的函数 且返回值类型为int
func oper(x, y int, fun func(int, int) int) int {
   //接收 xy参数
   r := fun(x, y)
   return r
}

func addd(a, b int) int {
   r1 := a + b
   return r1
}

func sub(a, b int) int {
   r3 := a - b
   return r3
}

高级:闭包

一个外层函数中,有内层函数,该内层函数中,会操作外层函数的局部变量并且该外层函数的返回值就是这个内层函数。
这个内层函数和外层函数的局部变量,统称为闭包结构。
局部变量的生命周期就会发生改变,正常的局部变量会随着函数的调用而创建,随着函数的结束而销毁但是闭包结构中的外层函数的局部变量并不会随着外层函数的结束而销毁,因为内层函数还在继续使用。

package main

import "fmt"

func main() {
	//定义一个变量 接受返回值(函数)
	r1 := increment()
	fmt.Println(r1)

	v1 := r1()
	fmt.Println(v1)
	//不断调用自增+1
	v2 := r1()
	fmt.Println(v2)
	//不断调用自增+1
	fmt.Println(r1())
	fmt.Println(r1())
	fmt.Println(r1())
	fmt.Println(r1())
	fmt.Println("====================")
	//	==========================================================
	r2 := increment()
	v3 := r2()
	fmt.Println(v3)
	fmt.Println(r2())
	fmt.Println(r2())
	fmt.Println(r2())
	fmt.Println(r1())
	fmt.Println(r2())
}

// 返回一个函数
func increment() func() int {

	//局部变量
	i := 0
	//定义一个匿名函数 给变量自增并返回
	fun := func() int {
		//内层函数,没有执行
		i++
		return i
	}
	return fun
}
/*
输出结果:
0xd5ea00
1
2
3
4
5
6
====================
1
2
3
4
7
5

*/
posted @   落暮つ  阅读(292)  评论(5编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示