名人说:莫愁千里路,自有到来风。 ——钱珝
创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊)目录
- 1、函数的概念与定义
- ①函数的概念
- ②函数的具体定义
- ③多返回值
- 2、函数参数与作用域
- ①可变参数
- ②形式参数与实际参数
- ③参数的传递细节
- ④函数作用域
- ⑤递归函数
- 3、小结
1、函数的概念与定义
①函数的概念
在Go语言中,函数是基本的代码块,用于执行一个任务。函数可以接受输入参数,并且可以返回一个或多个值。它们是组织和复用代码的基本单位。在Go中,函数也可以被当作变量,传递给其他函数,或者从其他函数返回。
②函数的具体定义
函数的定义包括函数名、参数列表、返回值列表和函数体。格式如下:
//func 函数名 (参数1 类型1,参数2 类型2...)(返回值类型)
func functionName(param1 type1, param2 type2) (returnType) {
// 函数体
}
案例1:自定义sub函数,并通过样例测试
//创作者:Code_流苏(CSDN)
package main
import "fmt"
func sub(x int, y int) int {
return x - y
}
func main() {
result := sub(6, 5)
fmt.Println("6 - 5 =", result)
}
案例2:加法,函数调用探析
package main
import "fmt"
/*
函数是基本的代码块,用于执行一个任务
*/
//main()主函数 程序的入口
func main() {
var x int
var y int
var z int
fmt.Println("请输入x和y的值:")
fmt.Scanf("%d%d", &x, &y)
//调用函数 函数名()
z = add(x, y)
fmt.Println(z)
}
//函数格式
//func 函数名(参数1,参数2...,参数类型) 返回值类型 {
// 函数体
// return 返回值
//}
func add(a, b int) int {
c := a + b
return c
}
③多返回值
Go语言支持函数返回多个值,这在处理错误或者需要返回多种数据时非常有用。
案例1:交换打印
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("hello", "world")
fmt.Println(a, b)
}
案例2:函数调用,多返回值
package main
import "fmt"
func main() {
//函数的调用
printinfo()
myprint("haha")
c := add2(2, 3)
myprintnum(c)
x, y := swap("yueliusu", "you do it!")
fmt.Println(x, y)
}
// 无参无返回值的函数
func printinfo() {
fmt.Println("printinfo")
}
// 有一个参数的函数
func myprint(msg string) {
fmt.Println(msg)
}
func myprintnum(x int) {
println(x)
}
/* 有两个参数的函数 */
// 有一个返回值的函数
func add2(a, b int) int {
c := a + b
return c
}
// 有多个返回值的函数
func swap(x, y string) (string, string) {
return y, x
}
2、函数参数与作用域
①可变参数
在Go语言中,函数的参数数量可以是可变的,称为可变参数。通过在参数类型前加上...
符号来表示。
案例1:求和
package main
import "fmt"
func sum(nums ...int) {
total := 0
for _, num := range nums {
total += num
}
fmt.Println(total)
}
func main() {
sum(1, 2)
sum(1, 2, 3)
}
案例2:不同参数
package main
import "fmt"
func main() {
getSum("hahah", 1, 2, 3, 4, 5, 6, 7)
}
//在Go中,可变参数通过在参数类型前加上省略号 ... 来指定。
//这种参数在函数内部表现为同类型的切片(slice)。
// 参数 ...参数类型 <------> 可变参数
func getSum(msg string, nums ...int) {
fmt.Println(msg)
sum := 0
for i := 0; i < len(nums); i++ {
fmt.Println(nums[i])
sum += nums[i]
}
fmt.Println("sum:", sum)
}
//若一个函数的参数有可变参数的同时还有其它参数,可变参数要放参数列表最后的位置
//一个函数的参数列表最多只能有一个可变参数
②形式参数与实际参数
-
形式参数
定义函数时,用于接收外部传入值的变量称为形式参数。(接收到)
-
实际参数
在调用函数时,传递给函数的实际值或变量称为实际参数。(传递给)
package main
func main() {
// 形参与实参要一一对应,顺序,个数,类型
// 实际参数
println(max(1, 2))
}
//形式参数:定义函数时,用于接收外部传入值的 变量 称为形式参数
//实际参数:在调用函数时,传递给函数的实际值或变量称为实际参数
// max函数,实现两个数值比较大小
// 形式参数
func max(num1, num2 int) int {
var result int
if num1 > num2 {
result = num1
} else {
result = num2
}
//函数定义时有说明返回值的类型,那么函数中必须使用return语句来返回值
return result
}
③参数的传递细节
Go语言中函数的参数是通过值传递的,这意味着函数接受的是参数值的一个副本。但是,如果参数是指针、切片或映射等引用类型,则函数可以修改原始数据。
-
引用传递
( 切片 )引用传递 操作的是数据的地址 如:slice、map、chan…
-
值传递
( 数组 )值传递 操作的是数据本身 如:基础数据类型int、string、bool、floa64、array、struct…
案例1:引用传递,数据修改
package main
import "fmt"
func modify(s []int) {
s[0] = 100
}
func main() {
a := []int{1, 2, 3}
modify(a)
fmt.Println(a) // 输出 [100, 2, 3],原始数据被修改
}
案例2:值传递,接收与修改数据
package main
import "fmt"
func main() {
//值传递
arr := [4]int{1, 2, 3, 4}
fmt.Println(arr)
//值传递:拷贝实际参数arr的值给形式参数arr2
update(arr)
fmt.Println("调用函数后数据被修改为:", arr)
//调用函数后,arr中的数据并未发生变化,说明是值传递
//修改arr2的值并不会影响到arr的值
//值传递:传递的是数据的副本,此时修改副本的数据,对原数据并不影响,究其根本在于二者并不在同一内存空间
//引用传递
//见下个案例
}
//值传递 操作的是数据本身 如:基础数据类型int、string、bool、floa64、array、struct...
//引用传递 操作的是数据的地址 如:slice、map、chan...
func update(arr2 [4]int) {
fmt.Println("arr2接收的数据:", arr2)
arr2[0] = 100
fmt.Println("arr2修改后的数据:", arr2)
}
案例3:引用传递,切片
package main
import "fmt"
func main() {
//定义一个切片
s1 := []int{1, 2, 3, 4}
fmt.Println("s1默认数据", s1)
update2(s1)
fmt.Println("调用函数后s1的数据为:", s1)
}
//引用传递,传递的是数据的地址,当修改该数据时,由于和原数据共处同一地址处,原数据也会随着修改
func update2(s2 []int) {
fmt.Println("s2 接收到的数据为:", s2)
s2[0] = 10
fmt.Println("s2[0]被修改后,s2的数据为:", s2)
}
④函数作用域
变量的作用域是程序中变量可以正常访问的范围。在Go中:
-
局部变量
函数内定义的变量,它只在函数体内部或语句块内部可见。
-
全局变量
函数外部定义的变量。
案例1:内部与外部
package main
import "fmt"
func main() {
x := "outside"
{
y := "inside"
fmt.Println(y) // 输出 inside
}
fmt.Println(x) // 输出 outside
// fmt.Println(y) // 编译错误:y在这里不可见
}
案例2:局部变量,就近原则
package main
import "fmt"
var num int = 50
// 全局变量是 在函数外部定义的 变量
// 局部变量是 在函数内或语句块内定义的 变量 。它们只能在其定义的函数或语句块内部被访问。
func main() {
//函数体内的局部变量
temp := 100
if b := 1; b <= 10 {
//语句体内的局部变量
temp := 50
fmt.Println(temp) //局部变量 遵循就近原则
fmt.Println(b)
}
fmt.Println(temp)
fmt.Println(num)
f1()
f2()
}
func f1() {
num := 40
fmt.Println(num)
}
func f2() {
fmt.Println(num)
}
⑤递归函数
递归函数是指一个函数在其定义中调用自己的函数。递归允许程序以简洁的方式解决复杂问题,在数据量小的时候,使用递过来实现是十分简便的,但是若数据量较大,不建议再使用递归函数来解决,因为这会占用太大的空间,程序效率较低。
因此,总结一下,使用递归时,一般需要注意以下几点:
- 确保有终止条件:递归函数必须有一个明确的终止条件,否则会无限递归下去,导致栈溢出错误。终止条件通常是一个或多个基案(base case),即最简单的问题实例,可以直接解答,不需要进一步递归。
- 注意栈空间的使用:每次函数调用时,都会在栈上为其分配空间来保存参数、局部变量和返回地址等信息。递归调用过深可能会耗尽栈空间,导致栈溢出。因此,对于可能导致深层递归的问题,需要谨慎设计递归逻辑,或考虑使用迭代等其他方法。
- 递归深度限制:在某些情况下,特别是处理大数据量或深度嵌套的数据结构时,考虑设置递归深度限制,以避免可能的栈溢出或过度消耗资源。
案例1:递归求阶乘
package main
import "fmt"
func factorial(n int) int {
if n == 0 {
return 1
}
return n * factorial(n-1)
}
func main() {
fmt.Println(factorial(5)) // 输出 120
}
案例2:递归求和
package main
import "fmt"
func main() {
sum := Sum(5)
fmt.Println(sum)
}
// 递归函数 函数自己调用自己
// 递归需要有出口,也就是边界条件,否则会无限调用下去,导致栈溢出,系统崩溃
func Sum(n int) int {
if n == 1 {
return 1
}
return Sum(n-1) + n
}
3、小结
- 什么是函数?函数定义
- 多个返回值的函数
- 多个参数、可变参数 …
- 参数的作用域( 小范围的可以用大范围的变量,反之则不行 )
- 递归函数(函数自己调用自己,可能会导致栈溢出 … ,需要有终止条件或限制)
很感谢你能看到这里,如有相关疑问,还请下方评论留言。
Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊)
希望本篇内容能对大家有所帮助,如果大家喜欢的话,请动动手点个赞和关注吧,非常感谢你们的支持!