go 语言 函数
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\n",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\n",sum)//30
sum=Add(10,20)
fmt.Printf("sum的值是:%d\n",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\n",a) //100 a没有被改变,值传递
Change1(&a)
fmt.Printf("a的值是:%d\n",a) //200 指针传递
var b []int
b = make([]int,20,30)
ChangeSlice(b) //切片传递
fmt.Printf("%#v\n",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\n",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\n",v) /100 200
}
var sum int
for i:=0;i<len(args);i++{ //len(args) 求出参数的长度
sum = sum + args[i] //args[i] 求出每个参数的值
}
fmt.Printf("%d\n",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\n",v)
}
var sum int
for i:=0;i<len(aaa);i++{
sum = sum + aaa[i]
}
fmt.Printf("%d\n",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\n",getSqrt(8))
fmt.Printf("%f\n",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,
}
} //斐波那契

浙公网安备 33010602011771号