1.函数声明:
func function_name (parameter list) (return_types) {
函数体
}
- func:函数由 func 开始声明
- function_name:函数名称,函数名和参数列表一起构成了函数签名。
- parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
- return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
- 函数体:函数定义的代码集合
下面的更进一步的说明:(跟上面是一样的,都是函数的声明)
func funcName(形参1 type[, 形参2 type...]) [([[返回变量1] type[, [返回变量2] type...]])] {
[return [返回变量1[, 返回变量2...]]]
}
a. 如果形参类型都一样,可以这样写: 形参1, 形参2 type, 同时返回变量也一样
b. 如果只有一个返回值或者无返回值, 可以去掉对应的()
c. 如果返回有返回值,该函数中最外层要有return语句
d. 返回语句(), 返回变量名可以省略
e. []表示可省略
f. 不支持默认参数
2. 函数的特点:
1)函数即是变量
x:=1
y:=x
上面的变量的赋值,即函数也可以像变量一样赋值
package main import( "fmt" ) func Add(a,b int)int{ return a + b } func main(){ var c func(int,int) int c =Add fmt.Printf("%p %T %p %T ",c,c,Add,Add)//0x497fe0 func(int, int) int 0x497fe0 func(int, int) int c和Add的内存地址是同一个, //说明c和Add使用同一块内存地址里保存的内容。c = Add只是又给内存的一块地址增加了一个名字。 sum:=c(10,20) fmt.Printf("sum的值是:%d ",sum)//30 sum=Add(10,20) fmt.Printf("sum的值是:%d ",sum)//30 c 和Add是等效的 }
2)回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
函数指针是指向函数的指针变量。因此“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。函数指针有两个用途:调用函数和做函数的参数。
type callback func(int,int)int // 定义一个带有两个int类型的参数,一个返回值 类型 为int类型的函数叫callback func Add(a,b int){ //定义回调函数 return a + b } func callbacktest(a, b int,callback callback) int{ //定义一个函数,把callback类型的函数当作参数传递给这个函数 return callback(a,b) //返回callback类型函数的结果,相当于调用回调函数 } func main(){ fmt.Println(callbacktest(20,30,Add)) //50 触发调用 }
3)函数参数传递方式
1.值传递
2.引用传递
⽆论是值传递,还是引⽤传递,传递给函数的都是变量的副本,不过,值传递是值的拷⻉。引⽤传递是地址的拷⻉,⼀般来说,地址拷⻉更为⾼效。⽽值拷⻉取决于拷⻉的对象⼤⼩,对象越⼤,则性能
越低。
map、 slice、 chan、指针、 interface默认以引⽤的⽅式传递
func Change(a int){ a = 200 } func Change1(a *int){ *a = 200 } func ChangeSlice(b []int){ b[0] = 100 b[1] = 200 b[5] = 500 } func TestValuePass(){ a:=100 Change(a) fmt.Printf("a的值是:%d ",a) //100 a没有被改变,值传递 Change1(&a) fmt.Printf("a的值是:%d ",a) //200 指针传递 var b []int b = make([]int,20,30) ChangeSlice(b) //切片传递 fmt.Printf("%#v ",b)//[]int{100, 200, 0, 0, 0, 500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }
4)命名返回值
func Minus(a,b int)(c int){ c = a+b return //省略了返回值的名字 } func cacl(a,b int)(sum,avg int){ sum = a+b avg = (a+b)/2 return 省略了返回值的名字 } func TestNamedRe(){ fmt.Printf("%d ",Minus(1000,2000)) //3000 sum,avg := cacl(1000,2000) fmt.Printf("sum 的值=%d avg的值=%d",sum,avg) //3000 1500 }
5)_标识符,⽤来忽略返回值:
func cacl(a,b int)(sum,avg int){ sum = a+b avg = (a+b)/2 return } func TestNamedRe(){ sum,_ := cacl(1000,2000) fmt.Printf("sum 的值=%d",sum) //3000 }
6)可变参数
func add(arg…int) int {
} 0个或者多个参数
func add(a int,arg…int) int { 1个或者多个参数
}
func add(a int,b int,arg…int) int { 2个或者多个参数
}
arg 可以被任意合法的标识符替代
其中arg是⼀个slice,我们可以通过arg[index]依次访问所有参数
通过len(arg)来判断传递参数的个数
func indefinite(args...int){ fmt.Println(args) // 打印出每个参数 100 200 for _,v:= range(args){ fmt.Printf("%d ",v) /100 200 } var sum int for i:=0;i<len(args);i++{ //len(args) 求出参数的长度 sum = sum + args[i] //args[i] 求出每个参数的值 } fmt.Printf("%d ",sum) //300 } func testindefinite(){ a := 100 b := 200 indefinite(a,b) }
同样是上面的indenifite(args …int)函数为例,在参数赋值时可以不用用一个一个的赋值,可以直接传递一个数组或者切片,特别注意的是在参数后加上“…”即可。
func indefinite(aaa...int){ fmt.Println(aaa) for _,v:= range(aaa){ fmt.Printf("%d ",v) } var sum int for i:=0;i<len(aaa);i++{ sum = sum + aaa[i] } fmt.Printf("%d ",sum) } func testindefinite(){ arr := []int{100, 200, 300} indefinite(arr...) indefinite(arr[:2]...) // a := 100 // b := 200 // indefinite(a,b) // 100 200 } //输出结果 [100 200 300] 100 200 300 600 [100 200] 100 200 300
3.匿名函数
匿名函数是指不需要定义函数名的一种函数实现方式。
在Go里面,函数可以像普通变量一样被传递或使用,Go语言支持随时在代码里定义匿名函数。
匿名函数由一个不带函数名的函数声明和函数体组成。匿名函数的优越性在于可以直接使用函数内的变量,不必申明。
直接看一个例子:
func main(){ getSqrt := func(a float64) float64 { //匿名函数需要赋值给一个变量来调用,需要有一个名字,否则无法调用。就跟调用变量一样,也是需要一个名字的。 return math.Sqrt(a) } fmt.Printf("%f ",getSqrt(8)) fmt.Printf("%f ",getSqrt(16)) } //运行结果 2.828427 4.000000
4.递归函数
⼀个函数调⽤⾃⼰,就叫做递归。
递归的设计原则
1)⼀个⼤的问题能够分解成相似的⼩问题
2)定义好出⼝条件
利用递归函数可以很方便的求解问题,例如阶乘、斐波那契数列
func factorial(n int)int{ if n ==1 { return 1 }else{ return factorial(n-1)*n } } func testfac(){ n:=factorial(5) fmt.Printf("%d",n) // 120 }//阶乘
func fibonacii(n int)int{ if n<=1 { return 1 } return fibonacii(n-1) + fibonacii(n-2) } func testfibonacii(){ for i:=0;i<10;i++{ n:=fibonacii(i) fmt.Printf("%d,",n) //1,1,2,3,5,8,13,21,34,55, } } //斐波那契