Go-函数 |青训营笔记

36 阅读4分钟

Go-函数

这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天

这也是我学习Go的第四天

什么是函数

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

函数的声明

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

func function_name([parameter list])[return_types]{
    函数体
}
  • 无参无返回值
  • 有一个参数
  • 有两个参数的函数
  • 有一个返回值的函数
  • 有多个返回值的函数
// 无参无返回值
func printinfo() {
    fmt.Println("printinfo")
}
​
// 有一个参数
func myprint(msg string) {
    println(msg)
}
​
// 有两个参数的函数
// 返回值
func add(a, b int) int {
    println(a + b)
    return a + b
}
//有多个返回值的函数
func addxy(a, b int)( int,int) {
    println(a + b)
    return a,b
}

可变参数

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

// 可变参数
func myfunc(arg ...int) {
    // arg ...int告诉go这个函数接收不定数量的参数,类型全是int
}
// main 主函数
func main() {
    getSum("123", 2, 3, 4, 5, 6)
}
​
​
// ...可变参数
func getSum(msg string,nums ...int) {
    sum := 0for i := 0; i < len(nums); i++ {
        fmt.Println(nums[i])
        //sum = sum+num[i]
        sum += nums[i]
    }
​
    fmt.Println("sum :", sum)
}

参数传递

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

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

值传递:传递的是数据的副本,修改数据,对于原始的数据没有影响

import "fmt"func main() {
    //值传递
    // 定义一个数组 【个数】类型
​
    arr := [4]int{1, 2, 3, 4}
    fmt.Println(arr)
    // 传递: 拷贝arr
    update(arr)
    fmt.Println("调用更新后的数据:", arr)
    //引用传递
​
}
​
func update(arr2 [4]int) {
    fmt.Println("arr2接收的数据", arr2)
    arr2[0] = 100
    fmt.Println("arr2修改的数据", arr2)
}

引用传递:slice 引用传递,变量在内存中是存放在一定的地址上的,修改变量实际是修改变量地址处的内存。

func main() {
    //切片,可以扩容的数组
    s1 := []int{1, 3, 2, 4}
    fmt.Println("传递的数据", s1)
    update2(s1)
    fmt.Println("调用更新的数据:", s1)
}
​
func update2(s2 []int) {
    fmt.Println("传递的数据", s2)
    s2[0] = 100
    fmt.Println("更新的数据", s2)
}
​

image.png

defer 延迟函数执行

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

func main() {
    f("1")
    f("2")
    defer f("3") // 延迟执行
    f("4")
}
func f(s string) {
    fmt.Println(s)
}

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

  • 你可以在函数中添加多个defer语句,当函数被执行到最后,这些defer语句会按照逆序执行,最后该函数返回,特别是当你进行一些打开资源的操作时,遇到错误需要提前返回,在返回前你需要关闭相应的资源,不然很容易造成资源泄漏等问题
  • 如果有很多调用defer,那么defer是采用后进先出(栈)模式
func main() {
    f("1")
    f("2")
    defer f("3") // 延迟执行
    f("4")
    defer f("8") // 延迟执行
    defer f("6") // 延迟执行
}
​
func f(s string) {
    fmt.Println(s)
}

image.png

函数高级

函数的数据类型

import "fmt"// func 本身也是一个数据类型
func main() {
    fmt.Printf("%T", f1)
}
​
func f1() {
​
}

image.png

匿名函数推导

func main() {
    f1()
    f2 := f1 //函数本身也是一个变量
    //赋值
    f2()
    // 匿名函数
    f3 := func() {
        fmt.Println("我是f3函数")
    }
    f3()
    // 省略写法
    func(a, b int) int {
        fmt.Println("我是f5函数")
        return a + b
    }(1, 2)
}
func f1() {
}

回调函数

函数可以作为参数传递。

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

import "fmt"func main() {
    r1 := add(1, 2)
    fmt.Println(r1)
​
    // add 为回调函数
    // add 作为参数
    r2 := oper(3, 4, add)
    fmt.Println(r2)
    // 匿名函数
    r4 := oper(8, 4, func(a int, b int) int {
        if b == 0 {
            fmt.Println("00000")
            return 0
        }
        return a / b
    })
    println(r4)
}
​
// 高阶函数
func oper(a, b int, f func(int, int) int) int {
    r := f(a, b)
    return r
}
​
func add(a, b int) int {
    return a + b
}

闭包

import "fmt"func main() {
    r1 := increment()
    println(r1)
​
    v1 := r1()
    println(v1)
    v2 := r1()
    fmt.Println(v2)
    fmt.Println(r1())
    fmt.Println(r1())
    fmt.Println(r1())
​
    //
    r2 := increment()
    v3 := r2()
    println(v3)
    fmt.Println(r1())
    fmt.Println(r2())
​
}
​
// 自增
func increment() func() int {
    //局部变量 i
    i := 0
    //定义一个匿名函数,给变量自增并返回
    fun := func() int { // 内层函数,害没有执行的
        i++
        return i
    }
    return fun
}
​