Go 语言 函数、init函数、匿名函数的使用

Go 语言 函数、init函数、匿名函数的使用

一、函数:

1.基本概念:

  1. 完成某一个功能的程序指令(语句)的集合,称为函数
  2. 在 go 中,函数分为:自定义函数系统函数

函数基本语法

func 函数名 (形参列表) (返回值列表) {

​ 执行语句…

​ return 返回值列表

}

简单栗子

  • 将简单的计算器功能封装成一个函数;
package main

import (
	"fmt"
)

func main(){

	var num1 float64
	var num2 float64
	var operator01 string

	fmt.Println("输入值:")
	fmt.Scanln(&num1)
	fmt.Println("输入运算符号")
	fmt.Scanln(&operator01)
	fmt.Println("输入值:")
	fmt.Scanln(&num2)

	result := calculator(num1, num2, operator01)
	fmt.Println("最终结果为:", result)
	
}

// 定义一个计算器的函数, 函数名小写, 因为在此包中引用
// 有函数名;函数接收的形参;返回值列表;执行语句;return 返回值列表
func calculator(n1 float64, n2 float64, operator string) (float64){
	var i float64 = 0
	switch operator {
		case "+":
			i = n1 + n2
		case "-":
			i = n1 - n2
		case "*":
			i = n1 * n2
		case "/":
			i = n1 / n2 		
		default:
			fmt.Println("输入超出范围")
	}
	return i
}

2.函数调用过程:

举个栗子

package main

import (
	"fmt"
)

func test(n1 int) {
	n2 :=  n1 + 1
	fmt.Println("test()函数  n2=", n2)
}
func main(){
	n1 := 20
	// 调用test()函数
	test(n1)
	fmt.Println("main()函数  n1=", n1)

}
// 输出结果:
test()函数  n2= 21
main()函数  n1= 20

分析上述流程

  1. 调用一个函数时,会给函数分配一个新的空间,编译器会通过自身的处理,让这个新的空间和其他的栈的空间区分开
  2. 每个函数对应的栈中,数据空间是独立的,不会混淆
  3. 当一个函数调用完成后,程序会销毁这个函数对应的栈空间

3.return 语句:

基本语法

func 函数名 (形参列表) (返回值列表) {

​ 执行语句…

​ return 返回值列表

}

  1. 若返回多个值时,在接收时,希望忽略某个值,则用_符号表示占位忽略。
  2. 若返回值只有一个,可以不写() 括号

举个栗子

  • 返回多个值的栗子:

    func main(){
    	fmt.Println("main()函数")
    	num1 := 20
    	num2 := 10 
    
    	// 调用count()函数
    	n3, n4 := count(num1, num2)
    	fmt.Printf("count函数的返回值n3=%d, n4=%d", n3, n4)
    
    }
    
    // 此函数返回两个值
    func count(n1 int, n2 int) (int, int) {
    	fmt.Println("进入count函数")
    	n3 := n1 + n2
    	n4 := n1 - n2
    	return n3, n4
    }
    // 输出如下
    main()函数
    进入count函数
    count函数的返回值n3=30, n4=10
    
  • 多个值,不接收,使用 _ 表示占位忽略 栗子:

    func main(){
    	fmt.Println("main()函数")
    
    	num1 := 20
    	num2 := 10 
    
    	// 调用count()函数 使用 _ 表示占位呼噜
    	n3, _ := count(num1, num2)
    	fmt.Printf("count函数的返回值n3=%d\n", n3)
    }
    
    // 此函数返回两个值
    func count(n1 int, n2 int) (int, int) {
    	fmt.Println("进入count函数")
    	n3 := n1 + n2
    	n4 := n1 - n2
    	return n3, n4
    }
    //输出结果:
    main()函数
    进入count函数
    count函数的返回值n3=30
    
  • 返回值只有一个,(返回值类型列表) 可以不写 ()

    func main(){
    	fmt.Println("main()函数")
        
    	num1 := 20
    	num2 := 10 
        
    	n5 := sum(num1, num2)
    	fmt.Printf("sum函数的返回值n5=%d\n", n5)
    
    }
    // 返回值只有一个, 可以不写 (返回值类型列表) 这个 "括号"
    func sum(n1 int, n2 int) int {
    	fmt.Println("进入sum函数")
    	n5 := n1 + n2
    	return n5
    }
    // 输出结果:
    main()函数
    进入sum函数
    sum函数的返回值n5=30
    

二、递归函数:

一个函数在函数体内又调用了本身,我们称为递归调用

举个栗子

package main

import (
	"fmt"
)

// 写一个递归函数
func test (n1 int) {
	if n1 > 2 {
		n1--
		test(n1)
	}
	fmt.Println("n1=", n1)
}
func main(){
	test(4)
}
// 输出结果:
n1= 2
n1= 2
n1= 3

注意事项

  1. 执行一个函数时,就新建一个受保护的独立空间(新函数栈)
  2. 函数的局部变量是独立的,不会相互影响。
  3. 递归必须得有终止条件,否则会出现无限递归。
  4. 一个函数执行完或遇到return,该函数本身也会被系统销毁

三、函数注意事项及使用细节:

  1. 函数的形参列表可有多个,返回值列表也可以有多个

  2. 形参列表和返回值列表的数据类型可以是值类型或引用类型

  3. 被本包文件或其它包文件使用首字母大写,类似public; 只能被本包文件使用首字母小写,类似privat

  4. 函数中的变量是局部的,函数外不生效。

  5. 基本数据类型数组默认都是值传参,进行值拷贝。在函数内部修改,不会影响到原来的值

  6. 若在函数内的变量能修改函数外的变量,可以传入变量的地址&,函数内以指针方式操作变量

    // 在函数内部, 修改函数外部的变量
    func update(number *int) {
    	// *number 表示 指针指向的值(20) + 20  *number 指向的值 变成了 40
    	*number = *number + 20
    	fmt.Println("new_num", *number)
    }
    
    func main(){ 
    	var num int = 20
    	// 传进去的参数是 num 的内存地址
    	update(&num)
    	fmt.Println("old_num", num)
    
    }
    // 输出结果:
    new_num 40
    old_num 40
    
  7. go 函数 不支持函数 重载,会报错函数重复定义

  8. 在go 中,函数也是一种数据类型,可赋值给一个变量,该变量就是一个函数类型的变量。通过变量可以对函数调用

    // 函数也是一种数据类型, 可以赋值一个变量, 该变量就是一个函数类型的变量, 可以通过变量来调用函数
    func sum(n1 int, n2 int) int {
    	fmt.Println("进入sum()函数...")
    	return n1 + n2
    }
    
    func main()  {
    	var i int = 1
    	var j int = 2
    	fmt.Println("进入main()函数...")	
    	result := sum
    	fmt.Printf("result的数据类型%T, sum的数据类型是%T\n", result, sum)
    
    	new_result := result(i, j)  // 等价于  new_result := sum(i, j)
    	fmt.Println("new_result", new_result)
    
    }
    // 输出结果如下:
    进入main()函数...
    result的数据类型func(int, int) int, sum的数据类型是func(int, int) int
    进入sum()函数...
    new_result 3
    
  9. 函数可以作为形参,并且调用

    // 函数可以当作一个形参传入
    func params(n1 int, n2 int) int {
    	return n1 + n2	
    }
    
    func sum(params func(int, int) int, num1 int, num2 int )int  {
    	return params(num1, num2)
    
    }
    func main() {
    	new_sum := sum(params, 10, 20)
    	fmt.Println("new_sum", new_sum)
    
    }
    // 输出结果:
    new_sum 30
    
  10. go 支持自定义数据类型

    • 案例一,自定义int类型:

      func main()  {
      	// 给int 取了别名, 在go中 myInt 和 int 虽然都是 int 类型, 但是go 认为 myInt 和 int 是两个类型
      	type myInt int 
      	var num1 myInt
      	var num2 int
      	num1 = 40
      	num2 = int(num1)  // 如果这里不转换会报错 
      	fmt.Println("num1=", num1, "num2=", num2)
      }
      // 输出结果:
      num1= 40 num2= 40
      
    • 案例二,自定义函数类型:

      // 自定义一个函数 数据类型
      type myFunType func (int, int) int
      
      // 将函数作为参数传递
      func  myFunc (funvar myFunType, n1 int, n2 int) int {
      	return funvar(n1, n2)	
      }
      
      // 运算函数
      func sum(num1 int, num2 int) int {
      	return num1 + num2
      }
      
      func main()  {
      	var i int = 10
      	var j int = 20
      	result := myFunc(sum, i, j)
      	fmt.Println("result=", result)
      }
      // 输出结果:
      result= 30
      
  11. 支持对函数返回值命名

    // 函数返回值命名
    func sum(num1 int, num2 int) (sum int, sub int)  {
    	sub = num1 - num2
    	sum = num1 + num2
    	return 	
    }
    func main()  {
    	var i int = 10
    	var j int = 20
    	
    	a, b := sum(i, j)
    	fmt.Printf("a=%v b=%v", a, b)
    }
    // 输出结果:
    a=30 b=-10
    
  12. go 支持可变参数:

    • 基本语法:

      func sum(args…) sum int {

      ​ // 执行语句

      }

      ​ args 是 slice 切片,通过 args[index],可以访问到每个值。(args可以随意命名)

    • 举个栗子,支持1到多个参数:

      // go 支持可变参数, 1 到多个参数
      func sum(num1 int, args... int) int {
      	t := num1
      	for i := 0; i < len(args); i++ {
      		t += args[i]
      	}
      	return t
      
      }
      func main()  {	
      	count := sum(10, 20, 30, 40, 50)
      	fmt.Printf("count=%v", count)
      }
      // 输出结果:
      count=150
      

四、init 函数的使用:

每一个源文件都可以包含一个 init 函数init 函数会在main函数前被调用

基本使用

// init函数 会在main 函数执行前 被调用
func init() {
	fmt.Println("执行init函数()...")
}
func main(){
	fmt.Println("执行main函数()...")
}
// 输出结果:
执行init函数()...
执行main函数()...

init 函数注意事项:

  1. 一个文件同事包含全局变量定义、init函数、main函数,则执行流程全局变量 —> init函数 —> main函数

    // 声明一个全局变量 test 
    var test = testFunc()
    func testFunc () int {	
    	fmt.Println("提供给变量的函数...")  // 先执行 1
    	return 100
    }
    
    // init函数 会在main 函数执行前 被调用
    func init() {
    	fmt.Println("执行init函数()...")  // 在执行 2
    }
    func main(){
    	fmt.Println("执行main函数()...")  // 最后执行 3
    }
    // 输出结果:
    提供给变量的函数...
    执行init函数()...
    执行main函数()...
    
  2. 如果引入的包都含有变量定义、init函数先执行包中的引入的全局变量、init函数:

五、匿名函数:

go 支持匿名函数。匿名函数就是没有名字的函数,若我们希望某个函数仅使用一次,就可以考虑使用匿名函数,匿名函数也可以实现多次调用

1.基本使用:

简单使用:

  1. 定义匿名函数时,就直接调用(这种方式匿名函数只能被调用一次)。

    func main(){
    	// 求两个数的和, 定义一个匿名函数, 仅能使用一次
    	result := func (n1 int, n2 int) int  {
    		return n1 + n2		
    	}(10, 20)
    	fmt.Println("result=", result)
    }
    // 输出结果:
    result=30
    
  2. 匿名函数赋给一个变量,在通过该变量来调用匿名函数

    func main()  {
    	// 给匿名函数一个变量, 通过调用匿名函数的变量进行操作
    	// 此时 变量 i 类型就是  函数变量, 我们可以通过 i()完成调用
    	i := func (num1 int, num2 int) int {
    		return num1 + num2
    	}
    	result := i(10, 20)
    	fmt.Println("result的结果为:", result)
    
    	result_01 := i(30, 40)
    	fmt.Println("result的结果为:", result_01)
    	
    }
    // 输出结果:
    result的结果为: 30
    result的结果为: 70
    

2.全局匿名函数:

如果将匿名函数赋给一个全局变量,那么这个匿名函数就是一个全局匿名函数

举个栗子

// 定义一个全局的匿名函数, 变量为MyFunc
var (
	MyFunc = func (num1 int, num2 int) int {
		return num1 + num2
	}
)

func main(){
	// 调用全局的匿名函数
	result := MyFunc(10, 20)
	fmt.Println("result", result)
}
// 输出结果:
result 30
发布了158 篇原创文章 · 获赞 172 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/Fe_cow/article/details/104030654
今日推荐