Golang面向过程编程-函数
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.什么是函数
简单的说函数的作用就是把程序里多次调用的相同的代码部分定义成一份,然后起个名字,所有的调用都只用这个名字就可以了。修改代码时,只需要改变函数体内的代码即可。Go 语言最少有个 main() 函数。你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。函数声明告诉了编译器函数的名称,返回类型,和参数。Go语言标准库提供了多种可动用的内置的函数。
二.函数的特点
1>.减少重复代码;
2>.使程序变得可扩展;
3>.使程序变得易维护;
三.函数的返回值
说简单点就是函数执行完毕之后,会用关键字return返回一个value,这个value就是返回值。案例如下:
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7 8 package main 9 10 11 import "fmt" 12 13 func Max(a, b int) int { //其中关键字“func”是声明一个叫Max的函数名,“a”和“b”是传递的参数,第一个int是指参数的类型,第二个int是指返回值的类型 14 if a > b { 15 return a //表示当“a”大于“b”时,返回函数“a” 16 }else { 17 return b //否则就返回“b”,其实这个else可以不用写,因为他们的执行结果是等效的。 18 } 19 } 20 21 func main() { //定义一个主函数,一个go程序运行起来不能没有主函数,当主函数结束时,就意味着程序的结束。 22 res := Max(100,200) //调用函数,需要按照你自己定义的函数类型进行传参数,否则会编译报错哟!用变量res来接受函数的返回值。 23 fmt.Printf("相比之下,最大的数字是:【%d】 ",res) 24 } 25 26 27 28 29 #以上代码执行结果如下: 30 相比之下,最大的数字是:【200】
四.函数的传参姿势
函数定义时指出,函数定义时有参数,该变量可称为函数的形参。形参就像定义在函数体内的局部变量。 但当调用函数,传递过来的变量就是函数的实参,函数可以通过两种方式来传递参数:
a>.值传递:指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
b>.引用传递:是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
在默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7 8 package main 9 10 import "fmt" 11 /* 12 传递类型 描述 13 值传递 值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。 14 引用传递 引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。 15 */ 16 17 18 func SwapName(a string, b string) (string, string) { //该函数主要的功能就是将字符串的位置发生了改变,前后颠倒了一下。 19 return b ,a 20 } 21 22 func Swap(p *string,q *string) { //这个函数就牛逼了,它是并每一交换字符串的位置,而是直接将变量名的值给调换了。 23 var temp string 24 temp = *p 25 *p = *q 26 *q = temp 27 } 28 29 func main() { 30 Name_1 := "尹正杰" 31 Name_2 := "饼干" 32 x,y := SwapName(Name_1,Name_2) 33 fmt.Println(x,y) //只是将变量的位置交换了一下,我们成这种传参方式为值传参。 34 fmt.Printf("执行Swap函数之前Name_1=[%s],Name_2=[%s] ",Name_1,Name_2) 35 Swap(&Name_1,&Name_2) //并没有交换变量的位置,而是交换了变量的value,我们成这种传参方式叫做引用传参。 36 fmt.Printf("执行Swap函数之后Name_1=[%s],Name_2=[%s] ",Name_1,Name_2) 37 } 38 39 40 #以上代码执行结果如下: 41 饼干 尹正杰 42 执行Swap函数之前Name_1=[尹正杰],Name_2=[饼干] 43 执行Swap函数之后Name_1=[饼干],Name_2=[尹正杰]
1.不定参数的传递
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7 8 package main 9 10 import ( 11 "fmt" 12 "reflect" 13 ) 14 15 func SpecificTypes(args ...int) { 16 for _, arg := range args { 17 fmt.Printf("当前参数是【%v】,其类型是【%v】 ",arg,reflect.TypeOf(arg)) 18 } 19 } 20 21 func main() { 22 list_1 := []int{5,4,3,2,1} 23 for _,v := range list_1{ 24 SpecificTypes(v) //传递了5个参数进去 25 } 26 Num_1 := 100 27 Num_2 := 200 28 SpecificTypes(Num_2,Num_1) //只传递了2个int类型的参数进去 29 } 30 31 32 33 34 #以上代码执行结果如下: 35 当前参数是【5】,其类型是【int】 36 当前参数是【4】,其类型是【int】 37 当前参数是【3】,其类型是【int】 38 当前参数是【2】,其类型是【int】 39 当前参数是【1】,其类型是【int】 40 当前参数是【200】,其类型是【int】 41 当前参数是【100】,其类型是【int】
2.任意类型的不定参数
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7 8 package main 9 10 import ( 11 "fmt" 12 "reflect" 13 ) 14 15 func AnyType(args ...interface{}) { //interface可谓大胃王,可以接受任何的数据类型。 16 fmt.Println(args) 17 for _,arg := range args{ 18 fmt.Printf("当前参数是【%v】,其类型是【%v】 ",arg,reflect.TypeOf(arg)) 19 } 20 } 21 22 func main() { 23 ArrayInt := []int{100,200,300} 24 ArrayString := []string{"yin","zheng","jie"} 25 ArrayBytes := []byte{'a','b','c'} 26 AnyType(ArrayInt,ArrayString,ArrayBytes) //可以传递任意类型的数据。 27 } 28 29 30 31 #以上代码执行结果如下: 32 [[100 200 300] [yin zheng jie] [97 98 99]] 33 当前参数是【[100 200 300]】,其类型是【[]int】 34 当前参数是【[yin zheng jie]】,其类型是【[]string】 35 当前参数是【[97 98 99]】,其类型是【[]uint8】
五.匿名函数
匿名函数是指不需要定义函数名的一种函数实现方式。1958年LISP首先采用匿名函数。 在Go里面,函数可以像普通变量一样被传递或使用,Go语言支持随时在代码里定义匿名函数。 匿名函数由一个不带函数名的函数声明和函数体组成。匿名函数的优越性在于可以直接使用函数内的变量,不必申明。
1>.匿名函数案例一,求某个数字的平方根。
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7 8 package main 9 10 import ( 11 "fmt" 12 "math" 13 ) 14 15 func main() { 16 GetSqrt := func(num float64)float64 { //定义一个名称叫做GetSqrt的匿名函数,特点是用func关键字定义时没有函数名,只有函数形参和返回值类型。 17 return math.Sqrt(num) //代码的结构体可以直接使用形参里面的参数,并将结果传给GetSqrt变量。 18 } 19 fmt.Println(GetSqrt(100)) //计算100的平方根。 20 fmt.Println(GetSqrt(64)) 21 fmt.Println(GetSqrt(25)) 22 } 23 24 25 26 #以上代码执行结果如下: 27 10 28 8 29 5
2>.匿名函数案例二,对数字进行排序;
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7 8 package main 9 10 11 import ( 12 "sort" 13 "fmt" 14 ) 15 16 17 func main() { 18 num := []int{2,400,1,5,3,9,700,6} //定义一个无序的切片; 19 sort.Slice(num, func(i, j int) bool { //利用sort包给字符串排序 20 return num[i] > num[j] 21 }) 22 fmt.Println(num) 23 } 24 25 26 27 #以上代码执行结果如下: 28 [700 400 9 6 5 3 2 1]
3>.匿名函数案例三,对字母进行排序;
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7 8 package main 9 10 11 import ( 12 "sort" 13 "fmt" 14 ) 15 16 type student struct { //定义一个机构体; 17 id int 18 name string 19 } 20 21 22 func main() { 23 str := []student{} //声明一个结构体 24 str = append(str,student{ 25 name:"EEEEE", 26 id:1, 27 }) 28 29 str = append(str,student{ 30 name:"CCCC", 31 id:2, 32 }) 33 34 str = append(str,student{ 35 name:"DDDDDD", 36 id:3, 37 }) 38 39 sort.Slice(str, func(i, j int) bool { 40 return str[i].name < str[j].name //按照字母排序 41 }) 42 fmt.Println(str) 43 44 sort.Slice(str, func(i, j int) bool { 45 return str[i].id < str[j].id //按照数字排序 46 }) 47 fmt.Println(str) 48 } 49 50 51 52 53 #以上代码执行结果如下: 54 [{2 CCCC} {3 DDDDDD} {1 EEEEE}] 55 [{1 EEEEE} {2 CCCC} {3 DDDDDD}]
六.递归函数
简单的说递归函数就是自己调用自己,但是你需要一定一个结束条件。那么有的小伙伴会问了,为什么要指定结束条件呢?因为调用递归函数的时候都会在系统内存中重新开辟出一块内存,如果你一直调用它不去给它一个终止点的话,物理内存很快就会被撑爆的。
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7 8 package main 9 10 import "fmt" 11 12 func FibonacciSequence(n int64) int64 { //这是定义斐波拉契数列的递归函数,其中数字n表示结束位置。 13 if n == 1 || n == 2 { 14 return 1 15 } 16 return FibonacciSequence(n-1) + FibonacciSequence(n-2) //指定结束条件 17 } 18 19 func main() { 20 fmt.Println(FibonacciSequence(40)) //第40个数字所对应的值。 21 } 22 23 24 25 #以上代码执行结果如下: 26 102334155
七.嵌套函数
嵌套函数,就是指在某些情况下,您可能需要将某函数作为另一函数的参数使用。
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7 8 package main 9 10 import ( 11 "strings" 12 "fmt" 13 ) 14 15 func Toupper(s string) string { //还函数是讲字母从小写转换成大写。 16 return strings.Map(func(r rune) rune { //类似python中的嵌套函数.即在函数里在定义了一个匿名函数。 17 return r - 32 18 },s) 19 } 20 21 func main() { 22 fmt.Println(Toupper("yinzhengjie")) 23 } 24 25 26 27 #以上代码执行结果如下: 28 YINZHENGJIE
八.闭包函数
闭包是由函数及其相关引用环境组合而成的实体(即:闭包=函数+引用环境)。 “官方”的解释是:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
我们知道return可以返回一个字符串或是一个整数型当然也是可以返回一个函数,我们利用它可以返回函数的特性,可以在调用该函数的时候拿到返回的函数,再去执行返回的函数,最终得到我们想要的结果,要注意的是这个返回的函数的是可以获取到定义它的函数的环境变量。拥有这种定义方式和调用方法的函数,我们称之为比包函数。
1>.利用闭包函数求和;
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7 8 package main 9 10 import "fmt" 11 12 func SummationOperation(n int64) func(int64) int64 { //定义一个函数,并且返回值应该是个函数。 13 return func(m int64) int64 { //返回一个匿名函数 14 return m + n //该匿名函数只有“m”形参,但是它可以获取到它的SummationOperation的一个形参“n”的值。 15 } 16 } 17 18 func main() { 19 sum := SummationOperation(100) //调用函数SummationOperation函数,由于它返需要返回一个匿名函数,因此我们需要用一个变量去接收。 20 fmt.Println(sum(20)) //由于匿名函数需要传入一个“int64”的数据类型进行相加操作,因此我们在调用的时候需要传入一个整形。 21 fmt.Println(sum(100)) 22 } 23 24 25 26 #以上代码执行结果如下: 27 120 28 200
2>.闭包函数挖坑(你会发现该函数存取的值总是最后一位的。)
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7 8 package main 9 10 import "fmt" 11 12 func main() { 13 var list []func() 14 for i :=0;i < 3 ; i++ { 15 list = append(list, func() { 16 fmt.Println(i) 17 //fmt.Println(&i) 18 }) 19 } 20 for _,f := range list{ 21 f() 22 } 23 } 24 25 26 27 28 #以上代码执行结果如下: 29 3 30 3 31 3
3>.闭包函数填坑
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7 8 package main 9 10 import "fmt" 11 12 func main() { 13 var list []func() 14 for i :=0;i < 3 ; i++ { 15 i := i //给i变量重新赋值, 16 list = append(list, func() { 17 fmt.Println(i) 18 //fmt.Println(&i) 19 }) 20 } 21 for _,f := range list{ 22 f() 23 } 24 } 25 26 27 28 29 #以上代码执行结果如下: 30 0 31 1 32 2
九.常用内置函数介绍
未完待续。。。。