初识golang之函数

vcity · · 3255 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

声明:
func funcName(input1 type1, intput2 type2) (output1 type1, output2 type2) {
    ………………
    //可以有多个返回值
    return val1, val2
}
说明:golang中通过func来声明一个函数,函数可以有一个或者多个参数,每个参数后面带类型,通过,分隔;函数可以返回多个值,返回的个数要于声明时定义的返回个数相同,声明时可以不写返回的变量名,而直接使用类型(如果只有一个返回值且不声明返回值变量,那么可以省略返回值的括号,如果没有返回值,那么就直接省略最后的返回信息定义)
例:
func SumAndProduct(a, b int) (int, int) {
    return a+b, a*b
}
func SumAndProduct(a, b int) (add int, Multiplied int) {
    add = a + b;
    Multiplied = a * b;
    return
}
这两段代码都是正确的,当定义函数时命令了返回参数变量时,可以直接返回而不用带变量名。注意:如果命令的返回参数跟函数代码块中的变量同名,他会被隐藏,此时需显示return返回结果;还有就是显式return会先修改命名返回值,然后再执行defer延迟语句。

参数之变参:
golang支持变参,变量中所有参数的类别必须是同一种,且必须是最后一个形参。函数内获取变参为一个slice。函数声明为:func FuncName(args ...int) { } args ...int 告诉go这个函数接受变参参数。 使用如sum(x[2:6]...)

参数的使用:
函数的参数都是进行拷贝赋值的,只是分为copy值和copy指针,传递指针使用“&变量名”,在函数声明中使用“变量名 *类型”,如:
func Add(num *int) int {
    *num = *num + 100
    return *num
}
使用,nmber := 100 Add(&number) fmt.Println(number)
go语言中,string,slice,map这三种类型实现的机制类似指针,所以可以直接传递,而不用取地址后传递指针。若函数需要改变slice长度,则仍需去地址传递指针。

匿名函数和闭包:

闭包和匿名函数经常一起使用,可以使用闭包来访问函数中的局部变量(被访问操作的变量为指针指向关系,操作的是同一个局部变量)如:

func closure(x int) (func(), func(int)) {
    fmt.Printf("初始值x为:%d,内存地址:%p\n", x, &x)
    f1 := func() {
        x = x + 5
        fmt.Printf("x+5:%d,内存地址:%p\n", x, &x)
    }
    f2 := func(y int) {
        x = x + y
        fmt.Printf("x+%d:%d,内存地址:%p\n", y, x, &x)
    }
    return f1, f2
}
func main() {
    func1, func2 := closure(10)
    func1()
    func2(10)
    func2(20)
}
输出结果为:
初始值x为:10,内存地址:0xc080000038
x+5:15,内存地址:0xc080000038
x+10:25,内存地址:0xc080000038
x+20:45,内存地址:0xc080000038


延迟语句defer:
golang中,有种语句defer语句,在函数执行到最后时,这些defer语句才会按照定义的逆序执行,等这些defer语句都执行完后,函数再返回。所有可以利用这个来进行资源安全关闭,解加锁,记录执行情况等。defer是采用先进后出的模式的,如栈。注意:定义的延迟操作,如有提供参数会发生值的拷贝,尽管这些函数在退出时才执行,但所使用的参数是在定义时的拷贝,拷贝的原则和变量的赋值原则一个,slice,map,channel是指针拷贝。

函数作为值、类型:
在golang中函数也是一种变量,可以使用type来定义它,它的类型就是所有拥有相同的参数,相同的返回值的一种类型
type TypeName func(input1 type1, input2 type2) (output1 type1, output2 type2)
函数作为类型就可以把这个类型的函数当作值来传递,如面向对象中的组合方法,如:
//声明一个函数类型
type handlerNum func(int) int

func Add(num int) int {
    sum := 0
    for i := 1; i <= num; i++ {
        sum += i
    }
    return sum
}

func  Product(num int) int {
    return (1 + 100) * 100 / 2
}

func Gauss (num int, h handlerNum) {
    return h(num)
}

Gauss(100, Add) 和 Gauss(100, Product)这两个函数得到的结果都是一样的。

Panic和Recover:
golang中没有异常机制,它不能抛出异常,而是使用了panic和recover机制,panic它会中断原有的控制流程,并进入一个恐慌流程中,当函数调用panic,原有函数的执行会被中断,但原有函数中的defer函数会正常的执行,然后函数返回到调用它的地方
。在调用的地方,函数的行为就像调用了panic,这一过程继续向上,直到发生panic的gorutine中所有调用的函数返回,此时程序退出。恐慌可以直接调用panic产生,也可以有运行时错误产生。recover可以让进入恐慌流程中的goroutine恢复过来,recover仅在defer延迟函数内部中有效,在正常的执行过程中,调用recover会返回nil,并且没有其他任务效果,如果当前的goroutine陷入恐慌,调用recover可以捕获panic的输入值,并恢复正常的程序执行。

main函数和init函数:
golang中的两个保留函数,init函数能够应用于所有的package,main函数只能应用于main包中,两个函数在定义时不能有任何的参数和返回值,一个package可以有多个init函数,但为了可读性强烈建议用户在一个package中每个文件只写一个init函数,而main函数有且一个存在main包中。
程序初始化和执行都起始于main包,如果main包还导入其他的包,那么会在编译时将他们依次导入,当一个包被多个包同时导入,那么它只会导入一次,当导入的包还引入了其他的包,那么还会先将其他包导入进来,然后再对这些包的包级常量和变量进行初始化,接着执行init函数,依次类推,等所有的被导入的包都加载完毕并初始化完毕后,就会开始对main包的包级常量和变量进行初始化,然后执行main包中的init函数,最后执行main函数。const->var->init->main的过程。

内置函数:
close:关闭channel。
len:获取string,array,slice的长度,map key的数量和buffer channel可用数据数量。
cap:获取array长度、slice容量,以及buffer channel的最大缓存容量。
new:对指定类型分配初始化过的内存空间(零值填充),并返回指针。
make:仅用于slice、map、channel指针赋值类型,除了初始化内存,还负责设置相关属性。
append:向slice尾部追加一个或多个元素。
copy:在不同的slice间复制数据,并返回复制的个数,如:copy(s1, s2[2:7])
panic/recover:错误处理
complex/real/imag:复数处理。

有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:vcity

查看原文:初识golang之函数

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3255 次点击  ∙  1 赞  
加入收藏 微博
上一篇:golang时间处理
下一篇:golang调用dll
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传