对于GoLang函数的定义或者说理解:
函数是结构化编程中最小的模块单元,日常开发过程中,将复杂的算法过程分解为若干个小任务(代码块),使程序的结构性更清晰,程序可读性提升,易于后期维护和让别人读懂你的代码。
另外为了更好的重用你的代码,可以把重复性的任务抽象成一个函数。
Go语言中使用关键词func来定义一个函数,并且左花括号不能另起一行,比如:
func聽hello(){聽聽聽//左花括号不能另起一行 聽聽聽聽println("hello") }
Go语言中定义和应用函数时,有如下需要注意的点:
聽函数无须前置声明
聽不支持命名嵌套定义,支持匿名嵌套
聽函数只能判断是否为nil,不支持其它比较操作
聽支持多返回值
聽支持命名返回值
聽支持返回局部变量指针
聽支持匿名函数和闭包
func聽hello() {聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽//左括号不能另起一行 } func聽add(x,y聽int)聽(sum聽int){聽聽聽聽//命名返回值 聽聽聽聽sum聽=聽x聽+聽y 聽聽聽聽return } func聽vals()(int,int){聽聽聽聽聽聽聽//支持多返回值 聽聽聽聽return聽2,3 } func聽a(){} func聽b(){} func聽add(x,y聽int)聽(*int){聽聽聽聽聽聽//支持返回局部变量指针 聽聽聽聽sum聽:=聽x聽+聽y 聽聽聽聽return聽&sum } func聽main(){ 聽聽聽聽println(a==b)聽聽聽聽聽聽聽//只能判断是否为nil,不支持其它比较操作 聽聽聽聽func聽hello()聽{聽聽聽聽聽聽//不支持命名嵌套定义 聽聽聽聽聽聽聽聽println("hello") 聽聽聽聽} }
具备相同签名(参数和返回值)的函数才视为同一类型函数,比如:
func聽hello()聽{ 聽聽聽聽fmt.Println("hello") } func聽say(f聽func()){聽 聽聽聽聽f() } func聽main(){ 聽聽聽聽f聽:=聽hello 聽聽聽聽say(f) }
参数:
Go语言中给函数传参时需要注意以下几点:
聽不支持默认参数
聽不支持命名实参
聽参数视作为函数的局部变量
聽必须按签名顺序传递指定类型和数量的实参
聽相邻的同类型参数可以合并
聽支持不定长变参,实质上是slice
func聽test(x,y聽int,聽s聽string,聽_聽bool){聽聽聽//相邻的同类型参数可以合并 聽聽聽聽return } func聽add(x聽,y聽int)聽int聽{聽聽//参数视作为函数的局部变量 聽聽聽聽x聽:=聽100聽聽聽聽聽聽聽聽聽聽聽聽//no聽new聽variables聽on聽left聽side聽of聽:= 聽聽聽聽var聽y聽int聽=聽200聽聽聽聽聽//y聽redeclared聽in聽this聽block 聽聽聽聽return聽x聽+y } func聽sum(nums聽...int)聽{聽//变参函数 聽聽聽聽total聽:=聽0 聽聽聽聽for聽_,聽num聽:=聽range聽nums聽{ 聽聽聽聽聽聽聽聽total聽+=聽num 聽聽聽聽} 聽聽聽聽fmt.Println(total) } func聽main(){ 聽聽聽聽//test(1,2,"s")聽聽聽聽聽聽聽//not聽enough聽arguments聽in聽call聽to聽test 聽聽聽聽test(1,2,"s",false) 聽聽聽聽nums聽:=聽[]int{1,聽2,聽3} 聽聽聽聽sum(nums...) }
不管传递的是指针、引用还是其它类型参数,都是值拷贝传递的,区别在于拷贝的目标是目标对象还是拷贝指针而已。
在函数调用之前,编译器会为形参和返回值分配内存空间,并将实参拷贝到形参内存。比如:
func聽test1(x聽*int){ 聽聽聽聽fmt.Printf("%p,聽%v\n",&x聽,x) } func聽main(){ 聽聽聽聽a聽:=聽0x100 聽聽聽聽p聽:=聽&a 聽聽聽聽fmt.Printf("%p,聽%v\n",聽&p,聽p) 聽聽聽聽test1(p) } 输出: 0xc42002c020,聽0xc42000a320 0xc42002c030,聽0xc42000a320 从结构中看出,聽实参和形参指向同一目标,但是传递的指针是被赋值了的
如果函数参数和返回值过多,可以将其封装成一个结构体类型,比如:
type聽serverOption聽struct{ 聽聽聽聽addr聽聽聽聽string 聽聽聽聽port聽int聽 聽聽聽聽path聽聽聽聽string 聽聽聽聽timeout聽time.Duration } func聽newOption()聽*聽serverOption{ 聽聽聽聽return聽&serverOption{ 聽聽聽聽聽聽聽聽addr:"127.0.0.1", 聽聽聽聽聽聽聽聽port:8080, 聽聽聽聽聽聽聽聽path:"/var/www", 聽聽聽聽聽聽聽聽timeout:聽time.Second聽*聽5, 聽聽聽聽}聽聽聽 } func聽(s聽*serverOption)server(){ 聽聽聽聽println("run聽server") } func聽main(){ 聽聽聽聽s聽:=聽newOption() 聽聽聽聽s.port聽=聽80 聽聽聽聽s.server() 聽聽聽聽for{} }
变参:
变参本质上是一个切片(slice),只能接收一到多个同类型参数,且必须放在参数列表尾部,比如:
func聽add(args聽...int)聽int聽{ 聽聽total聽:=聽0 聽聽for聽_,聽v聽:=聽range聽args聽{ 聽聽聽聽total聽+=聽v 聽聽} 聽聽return聽total } func聽main()聽{ 聽聽fmt.Println(add(1,2,3)) }
变参既然是切片,那是否可以直接传个切片或数组呢?
func聽test1(s聽string,聽a聽...int){ 聽聽聽聽fmt.Printf("%T,聽%v\n",聽a,聽a)聽聽聽聽//[]int,聽[1聽2聽3聽4] } { 聽聽聽聽a聽:=聽[4]int{1,2,3,4} 聽聽聽聽test1("s",聽a)聽聽聽聽聽//cannot聽use聽a聽(type聽[4]int)聽as聽type聽int聽in聽argument聽to聽test1聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽 聽聽聽聽test1("s",聽a[:]聽聽聽聽聽//cannot聽use聽a[:]聽(type聽[]int)聽as聽type聽int聽in聽argument聽to聽test1 聽聽聽聽test1("s",聽a[:]...)聽//切片展开 }
变参既然是切片,那么参数复制的是切片的本身,并不包括底层的数组,因此可以修改原数据,但是可以copy底层数据,防止原数据被修改,比如:
func聽test1(a聽...int){ 聽聽聽聽for聽i聽:=聽range聽a{ 聽聽聽聽聽聽聽聽a[i]聽+=聽100 聽聽聽聽} } func聽main(){ 聽聽聽聽a聽:=聽[4]int{1,2,3,4} 聽聽聽聽//聽b聽:=聽make([]int,0) 聽聽聽聽//聽copy(b,a[:])聽聽聽聽聽聽聽聽聽 聽聽聽聽//聽test1(b[:]...) 聽聽聽聽test1(a[:]...) 聽聽聽聽for聽i聽:=聽range聽a{ 聽聽聽聽聽聽聽聽fmt.Println(a[i]) 聽聽聽聽} }
本文出自 “博学于文,约之于礼” 博客,转载请与作者联系!
有疑问加站长微信联系(非本文作者)