Go:函数

时间:Aug. 6, 2018 分类:

目录:

function

  • Go函数不支持嵌套,重载和默认参数
  • 支持无需声明原型,不定长度变参,多返回值,命名返回值参数,匿名函数和闭包
  • 定义函数使用关键字func,且左大括号不能另起一行
  • 函数也可以作为一种类型使用

构建func

func A(a int, b string) (a, b, c int) {

}

或者

func A(a int, b string) (int, int, int) {

}

第一个括号内是需要传递的参数,第二个括号内为返回值,当然如果只有只有可以简写为下面

func A(a int, b string) int {

}

赋值的时候直接赋值即可,在函数创建的时候定义了返回值,也就是创建了内存地址

func A() (a, b, c int) {
    a, b, c = 1, 2, 3
    return a, b, c
}

当然可以不写返回值,直接写return也是ok的

传入的参数数量不确定

package main

import(
    "fmt"
)

func main(){
    A(1, 2, 3, 4, 5)
}

func A(a...int) {
    fmt.Println(a)
}

执行结果

[1, 2, 3, 4, 5]

对于不定长变参,必须放在所有传入参数的最后,传入的时候是一个slice。对于传入的数字是一个值拷贝

对于传入参数类型的确认

package main

import(
    "fmt"
)

func main(){
    a, b := 1, 2
    A(a, b)
    fmt.Println(a, b)
}

func A(a ...int) {
    a[0] = 3
    a[1] = 4
    fmt.Println(a)
}

执行结果

[3, 4]
1 2

传入的时候是一个值的拷贝,那和传入一个slice是什么区别呢

package main

import(
    "fmt"
)

func main(){
    s := []int(1, 2)
    A(s)
    fmt.Println(s)
}

func A(s []int) {
    a[0] = 3
    a[1] = 4
    fmt.Println(s)
}

执行结果

[3, 4]
[3, 4]

直接传入slice是传递的是内存地址

如果传入指针就会是是内存地址了

package main

import(
    "fmt"
)

func main(){
    a := 1
    A(&a)
    fmt.Println(a)
}

func A(a *int) {
    *a = 3
    fmt.Println(*a)
}

执行结果

3
3

go语言一切皆类型

package main

import(
    "fmt"
)

func main() {
    a := A
    a()
}

func A() {
    fmt.Println("func A")
}

执行结果

func A

匿名函数

package main

import(
    "fmt"
)

func main(){
    a := func() {
        fmt.Println("Func A")
    }
    a()
}

执行结果

func A

闭包

package main

import(
    "fmt"
)

func main(){
    f := closure(10)
    fmt.Println(f(1))
}

func closure(x int) func(int) int {
    return func(y int) int {
        return x + y
    }
}

执行结果

11

defer

  • 执行方式类似其他语言中的析构函数,在函数体执行结束后按照调用顺序的相反顺序逐个执行
  • 即使函数发生严重错误也会执行
  • 支持匿名函数的调用
  • 常用于资源清理,文件关闭,解锁以及记录时间等
  • 通过匿名函数配合return之后修改函数计算结果
  • 如果函数体内某个变量作为defer时匿名函数的参数,在定义defer时就获得了拷贝,否则就是引用地址
  • Go没有异常机制,需要通过panic/recover模式来处理错误
  • panic可以在任何地方引发,但是recover只能在defer调用的函数中有用

倒序执行

package main

import(
    "fmt"
)

func main(){
    fmt.Println("a")
    defer fmt.Println("b")
    defer fmt.Println("c")
}

执行结果

11

package main

import(
    "fmt"
)

func main(){
    for i := 0; i < 3; i++ {
        defer fmt.Println(i)
    }
}

执行结果

2
1
0

换一种方式

package main

import(
    "fmt"
)

func main(){
    for i := 0; i < 3; i++ {
        defer func(){
            fmt.Println(i)
        }()
    }
}

执行结果

3
3
3

func(){fmt.Println(i)}是一个匿名函数,加上后面的括号代表调用该函数

第一种是defer是获取了i的拷贝,而第二中在return后执行defer,defer获取的是i的引用,就是3,然后输出了三次

panic和recover

package main

import(
    "fmt"
)

func main(){
    A()
    B()
    C()
}

func A(){
    fmt.Println("func A")
}

func B(){
    defer func(){
        if err := recover(); err != nil {
            fmt.Println("Recover in B")
        }
    }() 
    panic("func B")
}

func C(){
    fmt.Println("func C")
}

执行结果

func A
Recover in B
func C