- 函数是一段代码的集合
- go语言中至少有一个main函数
- 函数可能需要一个结果,也可能没有
- 函数的格式:
* func func_name(参数1,参数2...) 返回类型{ return xxx }
1.函数的具体定义
- 无参无返回值
func printHello(){
fmt.Println("Hello")
}
- 有一个或多个参数的函数
func main() {
//调用max函数并输出最大值
fmt.Println(max(100,200))
}
//返回最大值
func max(num1 int,num2 int) int{
if num1>num2 { //比较两个数大小
return num1
}else{
return num2
}
}
- 有一个或多个返回值的函数
func main() {
fmt.Println(swap("100","200"))
}
func swap(x, y string) (string, string){
return y,x
}
func main() {
fun1(10,20)
}
//求周长和面积
func fun1(len,wid float64)(float64,float64){
//周长
zc := (len + wid)*2
fmt.Println("周长是:",zc)
//面积
mj := len * wid
fmt.Println("面积是:",mj)
return zc,mj
}
2.可变参数
- 一个函数的参数类型确定,个数不确定,可以使用可变参数
func main() {
fmt.Println(fun1(3,3,3))
}
//求和,参数可变
func fun1(num1 ...int) int {
sum := 0
//len(num1) 获取参数的长度
for i := 0; i < len(num1); i++ {
sum += num1[i]
}
return sum
}
3.延迟函数:defer
defer:一个函数或者方法被延迟执行,执行到最后时,逆序执行
func main() {
defer fmt.Println("最后执行")
fmt.Println("最先执行")
defer fun1()
}
func fun1() {
fmt.Println("第二执行")
}
4.匿名函数
匿名函数:没有名字的函数
func main() {
func () {
fmt.Println("这是匿名函数")
}()
}
将匿名函数赋值给其他变量,可多次调用
func main() {
func () {
fmt.Println("这是匿名函数")
}()
f1 :=func () {
fmt.Println("这是匿名函数")
}
f1()
}
5.回调函数
回调函数:将函数作为另一个函数的参数
高阶函数:接收另一个函数作为参数的函数
func main() {
//oper为高阶函数
oper(add)
}
func add(a,b int)int{
return a+b
}
//回调函数:将函数作为另一个函数的参数
func oper( fun func(int,int)int)int{
r:=fun(1,2)
fmt.Println(r)
return r
}
6.闭包
一个外层函数中,有内层函数,该内层函数中,会操作外层函数的局部变量并且该外层函数的返回值就是这个内层函数。这个内层函数和外层函数的局部变量,统称为闭包结构。
局部变量的生命周期就会发生改变,正常的局部变量会随着函数的调用而创建,随着函数的结束而销毁但是闭包结构中的外层函数的局部变量并不会随着外层函数的结束而销毁,因为内层函数还在继续使用go
package main
import "fmt"
// 是一种特殊的结构:闭包结构,违反了程序正常的生命周期。合法的使用。程序允许的一种特殊结构,变量作用域升级了。
// 什么时候用闭包: js (xxxxxxx.html 引用大量的第三方库:10个js库,js库中很多变量名是冲突的)
// js 很多框架都是闭包结构的,防止变量冲突,全局变量污染
// 我的代码里面的变量就不会和你代码里面的变量冲突了。解决一些变量作用域冲突的问题。
/*
闭包结构:
一个外层函数中,有内层函数,该内层函数中,会操作外层函数的局部变量并且该外层函数的返回值就是这个内层函数。
在闭包结构中:局部变量的生命周期就会发生改变,
正常的局部变量会随着函数的调用而创建,随着函数的结束而销毁
但是闭包结构中的外层函数的局部变量并不会随着外层函数的结束而销毁,因为内层函数还在继续使用.
// 由于垃圾回收期不会将闭包中的变量销毁,可能会造成内存泄漏。
*/
// 你的代码变量和你同事的变量冲突了,解决。 i 新建一个变量。 第三方库中的代码都是闭包结构实现的导出。
var i int = 10
func main() {
r1 := increment()
fmt.Println(r1) // 返回的是一个 increment() 内存函数,还没有执行
// -- 执行这个内层函数
//
v1 := r1()
fmt.Println(v1)
v2 := r1()
fmt.Println(v2)
fmt.Println(r1())
fmt.Println(r1())
fmt.Println(r1())
// 你写的代码是对的,但是结果不对,你的变量被污染了
fmt.Println("--------------------------")
// r2和r1指向同一个地址
r2 := increment() // 再次调用的时候 ,i = 0
v3 := r2()
fmt.Println(v3) // 1
//因为我们内层还是用i,还存在引用,系统不会销货这个i,保护,单独作用r1
fmt.Println(r1()) // 6 // 这里的i 并没有随着 第二次创建就被销毁归0,而是在内层函数继续调用着。
fmt.Println(r2()) // 2
// r1 名字 ----> 内存地址 &r1
fmt.Printf("%p\n", &r1)
fmt.Printf("%p\n", &r2)
}
// 自增函数
// increment() 函数返回值为 func() int 类型
func increment() func() int { // 外层函数,项目(很多的全局变量)
// 定义一个局部变量
i := 0
// 在外层函数内部定义一个匿名函数,给变量自增并返回。
fun := func() int {
i++
return i
}
return fun
}
如果我们想使用闭包结构来解决全局变量污染的问题,那我们就可以写一个闭包结构来创建执行的函数。
通过这个闭包结构创建的函数内部的变量,都在这个函数中作用,不会和其他函数冲突。
闭包结果的返回值是一个函数。这个函数可以调用闭包结构中的变量。