go函数

函数

package main

import (
	"fmt"
	//v2 "math/rand/v2"
	//"weak"
)

//
func add(a,b int,)int{
	//fmt.Println(c)
	return  a+b
}
//多个返回值
func add1(a,b int)(sun int,err error){
	sun=a+b
	return sun,err
}
//可变参数示例
func add2(a ...int)(sun int){
	for _,v:=range a{
		sun+=v
	}
	return
}
//前面这个string类型参数必须传,后面可变int类型参数可以不传
func add3(d string,c ...int)(sun int){
	for _,v:=range c{
		sun+=v
	}
	fmt.Println(d)
	return
}
func runForever(){
	for {

	}
}
//函数返回函数
func cal(op string,i ...int) func(){
	switch op{
	case "+":
		return func() {
			fmt.Println("这是加法")
		}
	case "-":
		return func() {
			fmt.Println("这是减法")
		}
	case "*":
		return func() {
			fmt.Println("这是乘法")
		}
	case "/":
		return func() {
			fmt.Println("这是除法")
		}
	case "%":
		return func() {
			fmt.Println("这是取余")
		}
	default:
		return  func() {
			fmt.Println("输入符号不正确")
		}
	}
}
//传递的参数也带有函数
func cal2(my func(i ...int) int ) int{
	return my()
}

func main(){
	q:=2
	s:=7
	t:=add(q,s)
	fmt.Println(t)
	//add函数赋值给a变量;注意不可带括号,带括号是调用
	a:=add
	//调用a变量函数返回值给c
	c:=a(5,8)
	fmt.Println(c)
	//调用
	cal2(func (i ...int) int{
		sun	:= 0
		for _,v :=range i{
			sun+=v
		}
		return sun
	})
}

  Go 语言中的闭包(Closure),简单理解就是:一个函数可以“记住”并访问它定义时所在作用域中的变量,即使这些变量所在的函数已经执行结束了

示例

package main

import "fmt"

func add() func() int {
	n := 0

	return func() int {
		n++
		return n
	}
}

func main() {
	f := add()

	fmt.Println(f()) // 1
	fmt.Println(f()) // 2
	fmt.Println(f()) // 3
}
执行结果
1
2
3

  为什么能一直加

执行:

f := add()

时:

n := 0

本来应该随着 add() 结束而销毁。

但是返回的匿名函数:
func() int {
    n++
    return n
}
引用了 n。

于是 Go 发现:

这个变量后面还要用,不能销毁。

所以 n 会一直保存在内存中。

形成:

f
 │
 ▼
匿名函数
 │
 ▼
n = 0 → 1 → 2 → 3
这就是闭包。

  示例2

func makeSuffix(suffix string) func(string) string {  //返回值是一个带有string返回的函数

	return func(name string) string {
		return name + suffix
	}
}
调用
func main() {

	jpg := makeSuffix(".jpg")

	fmt.Println(jpg("头像"))
	fmt.Println(jpg("风景"))
}
#执行结果
头像.jpg
风景.jpg
这里:

suffix

被匿名函数记住了。

即使:

makeSuffix()

已经结束。

匿名函数仍然可以访问:

suffix

  Go 闭包常见用途

1. 计数器

func counter() func() {
	count := 0

	return func() {
		count++
		fmt.Println(count)
	}
}
c := counter()

c() //1
c() //2
c() //3

2. 状态保存例如记录用户访问次数:

func visit() func() int {
	times := 0

	return func() int {
		times++
		return times
	}
}

延迟执行Go 经常配合:

defer
goroutine
for i := 0; i < 3; i++ {
	go func() {
		fmt.Println(i)
	}()
}
这里就涉及闭包捕获变量的问题。

  defer 关键字

defer 是 Go 中非常重要的关键字,它的作用是:

延迟执行某个函数,在当前函数返回之前执行。
理解
先登记
后执行

  示例

package main

import "fmt"

func main() {
	fmt.Println("1")

	defer fmt.Println("2")

	fmt.Println("3")
}
1
3
2
执行过程:
main开始
↓
打印1
↓
登记 defer fmt.Println("2")
(暂时不执行)
↓
打印3
↓
main 即将结束
↓
执行 defer
↓
打印2

  多个 defer(后进先出)

func main() {
	defer fmt.Println("A")
	defer fmt.Println("B")
	defer fmt.Println("C")
}
执行结果
C
B
A
压入:

A
B
C

弹出:

C
B
A
所以遵循:

LIFO(Last In First Out)

后进先出。

  最常见用途——关闭资源

file, err := os.Open("a.txt")
if err != nil {
	return
}

defer file.Close()
无论后面:

正常 return
出现错误
中途退出

都会执行:

file.Close()

避免资源泄露。

  函数里defer 的使用

package main
import (
	"fmt"
)
func d()(r int){
	defer func ()  {
		r ++
		
	}()
	return 10
}
func main(){
	fmt.Println(d())

}
//执行结果
11

  go 语言的错误处理机制

处理理念:开发函数时需要有一个返回值去告诉调用者是否成功,go设计者要求必须处理err,代码中大量会出现if err !=nil ;go设计者必须处理这个异常,防御编程

package main

import (
	"errors"
	"fmt"
)
func A() (int,error){
	return 0, errors.New("失败")
}
func main(){
	_,err:=A()
	if err !=nil{
		fmt.Println(err)
	}

}
执行结果
失败

  panic与recover

panic 函数会导致你的程序退出,不推荐;一般使用常景,一个服务启动必须依赖其他服务的时候,才使用panic;但是服务启动了,这个时候你某行代码种不小心执行panic那么不好意思你挂了。事故;架不住有些地方的代码写的不小心被动触发panic

recover 这个函数可以捕获到panic

1.defer 需要放在panic之前定义,另外recover 只有在defer调用的函数中才会生效

2.recover 处理后,逻辑并不会回复到panic 那个点去

3. 多个defer会形成栈,后定义的defer会先执行

 

 

 

 

 

 

posted @ 2026-06-13 11:18  烟雨楼台,行云流水  阅读(4)  评论(0)    收藏  举报