对于GoLang函数的定义或者说理解:

函数是结构化编程中最小的模块单元,日常开发过程中,将复杂的算法过程分解为若干个小任务(代码块),使程序的结构性更清晰,程序可读性提升,易于后期维护和让别人读懂你的代码。

另外为了更好的重用你的代码,可以把重复性的任务抽象成一个函数。

Go语言中使用关键词func来定义一个函数,并且左花括号不能另起一行,比如:

funchello(){//左花括号不能另起一行println("hello")}

Go语言中定义和应用函数时,有如下需要注意的点:

函数无须前置声明

不支持命名嵌套定义,支持匿名嵌套

函数只能判断是否为nil,不支持其它比较操作

支持多返回值

支持命名返回值

支持返回局部变量指针

支持匿名函数和闭包

funchello(){//左括号不能另起一行}funcadd(x,yint)(sumint){//命名返回值sum=x+yreturn}funcvals()(int,int){//支持多返回值return2,3}funca(){}funcb(){}funcadd(x,yint)(*int){//支持返回局部变量指针sum:=x+yreturn&sum}funcmain(){println(a==b)//只能判断是否为nil,不支持其它比较操作funchello(){//不支持命名嵌套定义println("hello")}}

具备相同签名(参数和返回值)的函数才视为同一类型函数,比如:

funchello(){fmt.Println("hello")}funcsay(ffunc()){f()}funcmain(){f:=hellosay(f)}

参数:

Go语言中给函数传参时需要注意以下几点:

不支持默认参数

不支持命名实参

参数视作为函数的局部变量

必须按签名顺序传递指定类型和数量的实参

相邻的同类型参数可以合并

支持不定长变参,实质上是slice

functest(x,yint,sstring,_bool){//相邻的同类型参数可以合并return}funcadd(x,yint)int{//参数视作为函数的局部变量x:=100//nonewvariablesonleftsideof:=varyint=200//yredeclaredinthisblockreturnx+y}funcsum(nums...int){//变参函数total:=0for_,num:=rangenums{total+=num}fmt.Println(total)}funcmain(){//test(1,2,"s")//notenoughargumentsincalltotesttest(1,2,"s",false)nums:=[]int{1,2,3}sum(nums...)}

不管传递的是指针、引用还是其它类型参数,都是值拷贝传递的,区别在于拷贝的目标是目标对象还是拷贝指针而已。

在函数调用之前,编译器会为形参和返回值分配内存空间,并将实参拷贝到形参内存。比如:

functest1(x*int){fmt.Printf("%p,%v\n",&x,x)}funcmain(){a:=0x100p:=&afmt.Printf("%p,%v\n",&p,p)test1(p)}输出:0xc42002c020,0xc42000a3200xc42002c030,0xc42000a320从结构中看出,实参和形参指向同一目标,但是传递的指针是被赋值了的

如果函数参数和返回值过多,可以将其封装成一个结构体类型,比如:

typeserverOptionstruct{addrstringportintpathstringtimeouttime.Duration}funcnewOption()*serverOption{return&serverOption{addr:"127.0.0.1",port:8080,path:"/var/www",timeout:time.Second*5,}}func(s*serverOption)server(){println("runserver")}funcmain(){s:=newOption()s.port=80s.server()for{}}

变参:

变参本质上是一个切片(slice),只能接收一到多个同类型参数,且必须放在参数列表尾部,比如:

funcadd(args...int)int{total:=0for_,v:=rangeargs{total+=v}returntotal}funcmain(){fmt.Println(add(1,2,3))}

变参既然是切片,那是否可以直接传个切片或数组呢?

functest1(sstring,a...int){fmt.Printf("%T,%v\n",a,a)//[]int,[1234]}{a:=[4]int{1,2,3,4}test1("s",a)//cannotusea(type[4]int)astypeintinargumenttotest1test1("s",a[:]//cannotusea[:](type[]int)astypeintinargumenttotest1test1("s",a[:]...)//切片展开}

变参既然是切片,那么参数复制的是切片的本身,并不包括底层的数组,因此可以修改原数据,但是可以copy底层数据,防止原数据被修改,比如:

functest1(a...int){fori:=rangea{a[i]+=100}}funcmain(){a:=[4]int{1,2,3,4}//b:=make([]int,0)//copy(b,a[:])//test1(b[:]...)test1(a[:]...)fori:=rangea{fmt.Println(a[i])}}