博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Golang 函数function
阅读量:5279 次
发布时间:2019-06-14

本文共 3630 字,大约阅读时间需要 12 分钟。

函数function

  • Go函数不支持嵌套、重载和默认参数
  • 但支持以下特性:

  1. 无需声明原型
  2. 不定长度变参
  3. 多返回值
  4. 命名返回值参数
  5. 匿名函数
  6. 闭包
  • 定义函数使用关键字func,且左大括号不能另起一行
  • 函数也可以作为一种类型使用

返回值及参数说明

func A(a int, b string) (int, string, int)  { //第一个小括号当中是你的参数列表,第二个小括号是你的返回值列表    }
func A(a, b, c int) (int, string, int)  {    //如果abc都是int型的话,可以按照这种方法进行简写,同样的方法也适用于返回值当中}
func A() (a, b, c int)  { //1:如果这样写的话就必须要命名返回值    //命名返回值和不命名返回值得区别}
func A() (int, int, int)  { //    //命名返回值和不命名返回值得区别    a, b, c := 1,2,3    return a,b,c    //如果此时没有命名返回值的时候,那么在返回值得时候就必须写上return a,b,c    //当然为了代码的可读性,这里我们规定必须return 的时候加上返回值名}

不定长变参

package mainimport "fmt"func main()  {    A(1,2,3,4,5,6,7)}func A(a ...int) {    // 这里采用的是不定长变参,不定长变参必须是参数的最后一个参数,后面不能再跟 b string这样的参数    fmt.Println(a)}
package mainimport "fmt"func main()  {    s1:= []int{1,2,3,4}    a,b :=1,2    A(a,b)    fmt.Println(a,b)    B(s1)    fmt.Println(s1)}func A(a ...int) {    //这里传进来的实际上是一个slice,引用类型    a[0] = 3    a[1] = 4    //尽管我们在函数A当中接收到的是一个slice,但是它得到的是一个值拷贝    //和直接传递一个slice的区别看函数B    fmt.Println(a)}func B(s []int)  {    //这里并不是传递一个指针进去,而是对这个slice的内存地址进行了一个拷贝    //这里还可以看到像int型、string型进行常规的参数传进去的话,只是进行了个值拷贝,slice传进去虽然也是拷贝,但是它是内存地址的拷贝    s[0] = 4    s[1] = 5    s[2] = 6    s[3] = 7    fmt.Println(s)    //在这里 我们看到我们在函数B当中的修改,实际上影响到了我们main函数当中的变量s1    //如果直接传递一个slice,它的修改就会影响到这个slice的本身}PS:值类型和引用类型进行函数传参拷贝是不一样的,一个是拷贝值,一个是拷贝地址
package mainimport (    "fmt")func main() {    a := 1    A(&a) //这里取出a的地址    fmt.Println(a)}func A(a *int) { //传递的是指针类型    *a = 2 //在操作的时候需要去它的值进行操作,这个时候函数A就可以改变原始a的值    fmt.Println(*a)}

函数类型的使用

package mainimport (    "fmt")func main() {    a := A    a() //这个时候是将A的函数类型赋值给a,在go语言当中一切皆是类型啊}func A() {    fmt.Println("Func A")}

匿名函数的使用

package mainimport (    "fmt")func main() {    a := func() {        //此时这个代码块就是一个匿名函数,这个函数本身没有名称,我们将她赋值给a,然后调用        fmt.Println("Func A")    }    a() //依然可以打印func A}

GO语言当中的闭包

package mainimport (    "fmt")func main() {    f := closure(10)    res1 := f(1)    fmt.Println(res1)    res2 := f(2)    fmt.Println(res2)}func closure(x int) func(int) int {    fmt.Printf("%p \n", &x)    return func(y int) int {        fmt.Printf("%p \n", &x)        return x + y    }}//这里可以看出3次打印x的地址都是一样的

defer

  • defer的执行方式类似其它语言中的析构函数,在函数执行体结束后按照调用顺序的相反顺序逐个执行
  • 即使函数发生严重错误也会执行
  • 支持匿名函数的调用
  • 通常用于资源清理、文件关闭、解锁以及记录时间等操作
  • 通过与匿名函数配合可在return之后修改函数计算结果
  • 如果函数体内某个变量作为defer时匿名函数的参数,则在定义defer时即已经获得了拷贝,否则则是引用某个变量的地址

  • GO没有异常机制,但有panic/recove模式来处理错误
  • Panic可以在任何地方引发,但recover只有在defer调用的函数中有效

package mainimport (    "fmt")func main() {    fmt.Println("A")    defer fmt.Println("B")    defer fmt.Println("C")}//PS:打印的结果就是A C B
package mainimport (    "fmt")func main() {    for i := 0; i < 3; i++ {        //defer fmt.Println(i)        defer func() {            fmt.Println(i)        }() //调用这个函数    }}//刚才直接打印的时候,是作为一个参数传递进去,运行到defer的时候是将这个i的值进行了一个拷贝,所以打印的是 2 1 0//这种情况下i一直是一个地址的引用,i一直引用的是局部变量的i,在退出这个循环体的时候 i已经变成了3,在main函数return的时候,开始执行defer语句,defer语句的时候i已经变成了3

异常机制

package mainimport (    "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("Panic in B")}func C() {    fmt.Println("Func C")}
package mainimport (    "fmt")func main() {    var fs = [4]func(){}    for i := 0; i < 4; i++ {        defer fmt.Println("defer i=", i) //这个i是传递进来的参数,所以是值得拷贝        defer func() {            fmt.Println("defer_closure i=", i) //这里的i是引用外部的i,所以循环结束后,i变成了4        }()        fs[i] = func() {            fmt.Println("closure i = ", i) //这里也是引用外部的i,所以循环结束后i变成了4        }    }    for _, f := range fs {        f()    }}

转载于:https://www.cnblogs.com/skymyyang/p/7659775.html

你可能感兴趣的文章
获取spring中所有的bean名称
查看>>
linux常用命令
查看>>
java DecimalFormat
查看>>
简单两步快速学会使用Mybatis-Generator自动生成entity实体、dao接口和简单mapper映射(用mysql和oracle举例)...
查看>>
Spring读书笔记-----Spring核心机制:依赖注入
查看>>
如何挂载阿里云的数据盘
查看>>
block extends include三者的差别跟用法
查看>>
服务器安全
查看>>
系统学习qsort1 尤其partition
查看>>
yield生成器对象返回Fiabs元素 分类: python 小练习 ...
查看>>
HDU 1001 Sum Problem
查看>>
BZOJ 1196 [HNOI2006]公路修建问题(二分答案+并查集)
查看>>
Android学习笔记1:初识框架
查看>>
bzoj 2005
查看>>
杜教筛模板
查看>>
浅谈委托事件
查看>>
装箱问题
查看>>
C++:重载全局new/delete实现跨平台多线程内存检测
查看>>
文法解释修改
查看>>
Spring中的@Controller和 @RestController 的区别以及@ReqeustMapping的作用
查看>>