函数的参数
# 一、函数的参数
# 1.1 参数的使用
形式参数:定义函数时,用于接收外部传入的数据,叫做形式参数,简称形参.
实际参数:调用函数时,传给形参的实际的数据,叫做实际参数,简称实参.
函数调用:
A:函数名称必须匹配
B:实参与形参必须一一对应:顺序,个数,类型
# 示例代码
package main
import "fmt"
func main() {
/*
函数的参数:
形式参数: 也叫行参.函数定义的时候,用于接收外部传入的数据的变量.
函数中,某些变量的数值无法确定,需要由外部传入数据.
实际参数: 也叫实参,函数调用的时候,给形参赋值的实际的数据.
函数调用:
1.函数名: 声明的函数名和调用的函数名要统一
2.实参必须严格匹配形参: 顺序,个数,类型,一一对应的.
*/
//1.求1-10的和
getSum(10)
//2.求1-20的和
getSum(20)
//3.求1-100的和
getSum(100)
//4.求两个整数的和
getAdd(10, 20)
getAdd2(1, 2)
fun1(1.3, 2.4, "hello")
}
//定义一个函数: 用于1-10的和
func getSum(n int) {
sum := 0
for i := 0; i <= n; i++ {
sum += i
}
fmt.Printf("1-%d的和是: %d\n", n, sum)
}
func getAdd(a int, b int) {
sum := a + b
fmt.Printf("%d + %d = %d\n", a, b, sum)
}
func getAdd2(a, b int) { // 参数的类型一致,可以简写在一起
fmt.Printf("a:%d,b:%d\n", a, b)
}
func fun1(a, b float64, c string) {
fmt.Printf("a:%.2f,b:%.2f,c:%s\n", a, b, c)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# 1.2 可变参
可变参数也就是传入多个参数
Go
函数支持变参.接受变参的函数是有着不定数量的参数的.为了做到这点,首先需要定义函数使其接受变参
func myfunc(arg ...int) {}
1
arg ...int
告诉Go
这个函数接受不定数量的参数.注意,这些参数的类型全部是int
.在函数体中,变量arg
是一个int
的slice
:
for _, n := range arg {
fmt.Printf("And the number is: %d\n", n)
}
1
2
3
2
3
# 示例代码
package main
import "fmt"
func main() {
/*
可变参数:
概念: 一个函数的参数的类型确定,但是个数不确定,就可以使用可变参数.
语法:
参数名 ... 参数类型
对于函数,可变参数相当于一个切片.
调用函数的时候,可以传入0-多个参数.
Println(),printf(),Print()
append()
注意事项:
A、如果一个函数的参数是可变参数,同时还有其他的参数,可变参数要放在参数列表的最后.
B、一个函数的参数列表最多只能有一个可变参数.
*/
//1.求和
getSum()
getSum(1, 2, 3, 4, 5, 6, 7)
getSum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
//2.切片
s1 := []int{1, 2, 3, 4, 5}
getSum(s1...)
}
func getSum(nums ...int) {
//fmt.Printf("%T\n", nums) //[]int的切片
sum := 0
for i := 0; i < len(nums); i++ {
sum += nums[i]
}
fmt.Println("总和是: ", sum)
}
//func fun1(s1,s2 string,nums ... float64) {
//
//}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 1.3 参数传递
go
语言函数的参数也是存在值传递和引用传递- 函数运用场景
# 值传递
package main
import (
"fmt"
"math"
)
func main(){
/* 声明函数变量 */
getSquareRoot := func(x float64) float64 {
return math.Sqrt(x)
}
/* 使用函数 */
fmt.Println(getSquareRoot(9))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 引用传递
- 这就牵扯到了所谓的指针.知道,变量在内存中是存放于一定地址上的,修改变量实际是修改变量地址处的内
存.只有
add1
函数知道x
变量所在的地址,才能修改x
变量的值.所以需要将x
所在地址&x
传入函数,并将函数的参数的类型由int
改为*int
,即改为指针类型,才能在函数中修改x
变量的值.此时参数仍然是按copy
传递的,只是copy
的是一个指针.请看下面的例子
package main
import "fmt"
//简单的一个函数,实现了参数+1的操作
func add1(a *int) int { // 请注意,
*a = *a+1 // 修改了a的值
return *a // 返回新值
}
func main() {
x := 3
fmt.Println("x = ", x) // 应该输出 "x = 3"
x1 := add1(&x) // 调用 add1(&x) 传x的地址
fmt.Println("x+1 = ", x1) // 应该输出 "x+1 = 4"
fmt.Println("x = ", x) // 应该输出 "x = 4"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- 传指针使得多个函数能操作同一个对象.
- 传指针比较轻量级
(8bytes)
,只是传内存地址,可以用指针传递体积大的结构体.如果用参数值传递的话, 在每次copy
上面就会花费相对较多的系统开销(内存和时间).所以当要传递大的结构体的时候,用指针是一个明智的选择. Go
语言中slice
,map
这三种类型的实现机制类似指针,所以可以直接传递,而不用取地址后传递指针.(注:若函数需改变slice
的长度,则仍需要取地址传递指针)
# 示例代码
package main
import "fmt"
func main() {
/*
数据类型:
一、按照数据类型来分
基本数据类型:
int,float,string,bool
复合数据类型:
array,slice,map,struct,interface......
二、按照数据的存储特点来分:
值类型的数据: 操作的是数值本身
int,float64,bool,string,array
引用类型的数据: 擦了做的是数据的地址
slice,map,chan
参数传递:
A、值传递: 传递的是参数的副本.修改数据,对于原始的数据没有影响的.
值类型的数据,默认都是值传递: 基本数据类型,array,struct
B、引用传递: 传递的是数据的地址.导致多个变量指向同一块内存.
引用类型的数据,默认都是引用传递: slice,map,chan
*/
arr1 := [4]int{1, 2, 3, 4}
fmt.Println("函数调用前,数组的数据: ", arr1)
arr2(arr1)
fmt.Println("函数调用后,数组的数据: ", arr1)
fmt.Println("---------------------------")
s1 := []int{1, 2, 3, 4}
fmt.Println("函数调用前,切片的数据: ", s1)
fun2(s1)
fmt.Println("函数调用后,切片的数据: ", s1)
}
func fun2(s2 []int) { // s2 = s1 ,切片是引用类型,这里s2存储的是s1数据的底层数据地址;也就等同于s2中存储的数据和s1中存储的数据是同一个
fmt.Println("函数中,切片的数据: ", s2)
s2[0] = 100 // 这里s1中的`0`值也会发生变化,因为s2和s1操作的同一组数据
fmt.Println("函数中,切片的数据更改后: ", s2)
}
func arr2(arr2 [4]int) { //arr2 = arr1 ,因为数组是值类型;所以这里会把arr1中的数据copy给arr2
fmt.Println("函数中,数组的数据: ", arr2)
arr2[0] = 100 // 这里只有arr2的`0`值会发生变化,因为arr2是单独拷贝的一份arr1一样的数据
fmt.Println("函数中,数组的数据修改后: ", arr2)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
上次更新: 2024/04/09, 16:48:42
- 01
- AWS NAT-NetWork-Firwalld配置(一)04-09
- 02
- AWS NAT-NetWork-Firwalld配置(二)04-09
- 03
- kubernetes部署minio对象存储01-18