go破冰之旅·8·go函数基本实践及各种玩法
一次5-10分钟即可搞定,以干货+效率的学习方式带你更直观的玩转各种玩法!
行文不易,一字一句纯手打创造,倾注了不少精力,感谢支持。
目录
什么是函数?有哪些元素?
函数参数、返回值
小程序:函数与函数调用,各种玩法举一反三
函数参数与值传递说明
什么是函数?有哪些元素?
函数是一个基本的代码块,可以让每个函数代表一个基本职能,或者说定义要做的功能或任务;
一个完整的go程序中至少有个main函数,单个函数可声明函数名称、参数列表、返回值列表,定义函数需要用func关键字。
同时,go中的函数也是一个变量,可以在函数内继续定义函数。
其中init和main这两个内置函数的作用功能在前面讲解包时已充分说明,这里不再赘述哦!
函数参数、返回值
下面我们快速看一下函数的组成和表示:
// 示例1
func funcName(a int, b string) (string, int) {
// 函数体
return "",0
}
【说明】
函数名称:funcName
参数列表:两个参数,分别是a、b,类型分别为int、string
返回值列表:两个返回值,类型分别为string、int,且没有定义返回值名称
// 示例2
func funcName(a,b int) (sum int) {
// 函数体
return
}
【说明】
函数名称:funcName
参数列表:两个参数,分别是a、b,类型都为int类型
返回值列表:单个返回值,定义为sum变量,为int类型
函数的参数用来做输入条件,返回值用来返回结果。
以一个常见的过程说明该模型:你要计算a+b的和,假设a+b=c,那我们这个函数要做的就是计算两数之和,返回的结果就是计算所得的和,而函数的参数就是a和b,也就是输入的条件,得告诉函数要以什么为条件让它去执行。当然。参数列表和返回值列表也都可以不设置。
小程序:函数与函数调用,各种玩法举一反三
下面写一个简单程序来认识一下函数到底怎么定义和使用。
程序完成求和、求积两个职能,下面我们根据实际含义定义两个函数:
// 两数之和
func add(a, b int) int {
return a + b
}
// 两数之积
func multiply(a, b int) int {
return a * b
}
在main中调用并打印结果:
import "fmt"
func main() {
var a, b = 1, 2
// 求a+b的和
r1 := add(a, b)
fmt.Printf("a+b= %v\n", r1)
// 求a*b的积
r2 := multiply(a, b)
fmt.Printf("a*b= %v\n", r2)
}
这样就完成了函数调用和返回值的接收,结果:
a+b= 3
a*b= 2
另外,如果add函数我不想定义在外面,只想在本程序中唯一使用,也可以这么玩:
func main() {
var a, b = 1, 2
add0 := func(a, b int) int {
return a + b
}
// 求a+b的和
r1 := add0(a, b)
fmt.Printf("a+b= %v\n", r1)
// 求a*b的积
r2 := multiply(a, b)
fmt.Printf("a*b= %v\n", r2)
}
// 两数之积
func multiply(a, b int) int {
return a * b
}
可以看到在要求和的上方直接定义了一个函数add0,并且在接下来完成了调用,结果效果和上面完全一致。
当然,你觉得函数只有在这一个地方用到,为什么还要写函数名,让我直接调用岂不更简单?当然可以,咱们这么玩:
var a, b = 1, 2
// 求a+b的和
r1 := func(a, b int) int {
return a + b
}(a, b)
fmt.Printf("a+b= %v\n", r1)
r1就是对a、b求和的结果,效果也是完全一样,注意这个示例中func后的a、b也是函数参数,实际输入的1和2这两个参数是通过函数后的小括号传进去的,这个就是实际参数,而func后的a、b是形式参数,也叫形参。
同时在这个案例中,该func就是一个匿名函数,即没有名称的函数。
函数参数与值传递说明
值得注意的是,go中主要是值传递,并没有引用传递,所谓值传递就是形式参数是对应值的一个副本,传的并不是值本身。
假设我们有这样一个需求,函数updateNum修改输入参数n的值,将值恒定改为1,分为两种,返回修改的结果、不返回修改的结果:
func updateNum (n int) int{
n = 1
return n // 实际这里直接return 1就行了,但为了看起来更明白因此多此一举加了n = 1
}
func updateNum (n int){
n = 1
}
要说明的是,返回结果这种情况只要调用方去接收函数的返回值,则接收到的必定是1,因此没有悬念,这种严格说算不上修改返回值,而是直接返回了1,下面重点看看第二种:
n := 10
fmt.Printf("n=%d\n", n)
updateNum(n)
fmt.Printf("n=%d\n", n)
上面提到,go中默认是值传递,因此传入updateNum的参数为n的副本,函数只是传入了10而已,n本身还是n,函数内部所做的n=1实际修改的是函数的形参的值,外界的n不受影响,因此修改前后打印的n结果都是10。
那怎样才能让这个函数成功的修改了n呢?答案就是指针,给函数参数传递n的地址即可:
func main() {
n := 10
fmt.Printf("n=%d\n", n)
updateNum(&n)
fmt.Printf("n=%d\n", n)
}
func updateNum(n *int) {
*n = 1
}
这样修改为什么能成功,原因就是传入了n的地址,通过地址修改了变量内存地址对应的值,修改后外界会一同修改,因此在调用结束函数后再次打印,n就变成了1。这实际就是其它语言中听到的引用传递。
在后续熟悉了其它引用类型后,这会变得更加有趣!
到这里,相信你对函数的使用和玩法也有了一个清晰的认识啦。
在后续熟悉了引用类型及指针结合并逐渐加深后也可以阅读这篇(不包含在本文范畴内,目前阶段暂不必须):
关于go语言指针/指针指向的全面分析
来进一步加强这方面的全面理解。